2007-07-17 18:37:06 -07:00
/*
* xen console driver interface to hvc_console . c
*
* ( c ) 2007 Gerd Hoffmann < kraxel @ suse . de >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/console.h>
# include <linux/delay.h>
# include <linux/err.h>
2012-08-06 15:27:09 +01:00
# include <linux/irq.h>
2007-07-17 18:37:06 -07:00
# include <linux/init.h>
# include <linux/types.h>
2012-01-30 16:02:31 +00:00
# include <linux/list.h>
2007-07-17 18:37:06 -07:00
2012-01-27 18:31:36 +00:00
# include <asm/io.h>
2007-07-17 18:37:06 -07:00
# include <asm/xen/hypervisor.h>
2009-10-06 15:11:14 -07:00
# include <xen/xen.h>
2012-01-27 18:31:36 +00:00
# include <xen/interface/xen.h>
# include <xen/hvm.h>
2012-01-30 16:02:31 +00:00
# include <xen/grant_table.h>
2007-07-17 18:37:06 -07:00
# include <xen/page.h>
# include <xen/events.h>
# include <xen/interface/io/console.h>
2012-08-06 15:27:09 +01:00
# include <xen/interface/sched.h>
2007-07-17 18:37:06 -07:00
# include <xen/hvc-console.h>
2012-01-30 16:02:31 +00:00
# include <xen/xenbus.h>
2007-07-17 18:37:06 -07:00
# include "hvc_console.h"
# define HVC_COOKIE 0x58656e /* "Xen" in hex */
2012-01-30 16:02:31 +00:00
struct xencons_info {
struct list_head list ;
struct xenbus_device * xbdev ;
struct xencons_interface * intf ;
unsigned int evtchn ;
struct hvc_struct * hvc ;
int irq ;
int vtermno ;
grant_ref_t gntref ;
} ;
static LIST_HEAD ( xenconsoles ) ;
static DEFINE_SPINLOCK ( xencons_lock ) ;
2007-07-17 18:37:06 -07:00
/* ------------------------------------------------------------------ */
2012-01-30 16:02:31 +00:00
static struct xencons_info * vtermno_to_xencons ( int vtermno )
{
struct xencons_info * entry , * n , * ret = NULL ;
if ( list_empty ( & xenconsoles ) )
return NULL ;
list_for_each_entry_safe ( entry , n , & xenconsoles , list ) {
if ( entry - > vtermno = = vtermno ) {
ret = entry ;
break ;
}
}
2008-05-26 23:31:25 +01:00
2012-01-30 16:02:31 +00:00
return ret ;
}
static inline int xenbus_devid_to_vtermno ( int devid )
2007-07-17 18:37:06 -07:00
{
2012-01-30 16:02:31 +00:00
return devid + HVC_COOKIE ;
2007-07-17 18:37:06 -07:00
}
2012-01-30 16:02:31 +00:00
static inline void notify_daemon ( struct xencons_info * cons )
2007-07-17 18:37:06 -07:00
{
/* Use evtchn: this is called early, before irq is set up. */
2012-01-30 16:02:31 +00:00
notify_remote_via_evtchn ( cons - > evtchn ) ;
2007-07-17 18:37:06 -07:00
}
2012-01-30 16:02:31 +00:00
static int __write_console ( struct xencons_info * xencons ,
const char * data , int len )
2007-07-17 18:37:06 -07:00
{
XENCONS_RING_IDX cons , prod ;
2012-01-30 16:02:31 +00:00
struct xencons_interface * intf = xencons - > intf ;
2007-07-17 18:37:06 -07:00
int sent = 0 ;
cons = intf - > out_cons ;
prod = intf - > out_prod ;
mb ( ) ; /* update queue values before going on */
BUG_ON ( ( prod - cons ) > sizeof ( intf - > out ) ) ;
while ( ( sent < len ) & & ( ( prod - cons ) < sizeof ( intf - > out ) ) )
intf - > out [ MASK_XENCONS_IDX ( prod + + , intf - > out ) ] = data [ sent + + ] ;
wmb ( ) ; /* write ring before updating pointer */
intf - > out_prod = prod ;
2010-10-14 11:38:47 -07:00
if ( sent )
2012-01-30 16:02:31 +00:00
notify_daemon ( xencons ) ;
2007-07-17 18:37:06 -07:00
return sent ;
}
2010-09-02 16:17:06 +01:00
static int domU_write_console ( uint32_t vtermno , const char * data , int len )
2009-10-20 15:28:21 +09:00
{
int ret = len ;
2012-01-30 16:02:31 +00:00
struct xencons_info * cons = vtermno_to_xencons ( vtermno ) ;
if ( cons = = NULL )
return - EINVAL ;
2009-10-20 15:28:21 +09:00
/*
* Make sure the whole buffer is emitted , polling if
* necessary . We don ' t ever want to rely on the hvc daemon
* because the most interesting console output is when the
* kernel is crippled .
*/
while ( len ) {
2012-01-30 16:02:31 +00:00
int sent = __write_console ( cons , data , len ) ;
2009-10-20 15:28:21 +09:00
data + = sent ;
len - = sent ;
if ( unlikely ( len ) )
HYPERVISOR_sched_op ( SCHEDOP_yield , NULL ) ;
}
return ret ;
}
2010-09-02 16:17:06 +01:00
static int domU_read_console ( uint32_t vtermno , char * buf , int len )
2007-07-17 18:37:06 -07:00
{
2012-01-30 16:02:31 +00:00
struct xencons_interface * intf ;
2007-07-17 18:37:06 -07:00
XENCONS_RING_IDX cons , prod ;
int recv = 0 ;
2012-01-30 16:02:31 +00:00
struct xencons_info * xencons = vtermno_to_xencons ( vtermno ) ;
if ( xencons = = NULL )
return - EINVAL ;
intf = xencons - > intf ;
2007-07-17 18:37:06 -07:00
cons = intf - > in_cons ;
prod = intf - > in_prod ;
mb ( ) ; /* get pointers before reading ring */
BUG_ON ( ( prod - cons ) > sizeof ( intf - > in ) ) ;
while ( cons ! = prod & & recv < len )
buf [ recv + + ] = intf - > in [ MASK_XENCONS_IDX ( cons + + , intf - > in ) ] ;
mb ( ) ; /* read ring before consuming */
intf - > in_cons = cons ;
2012-01-30 16:02:31 +00:00
notify_daemon ( xencons ) ;
2007-07-17 18:37:06 -07:00
return recv ;
}
2010-09-02 16:17:06 +01:00
static struct hv_ops domU_hvc_ops = {
. get_chars = domU_read_console ,
. put_chars = domU_write_console ,
2008-06-20 15:24:08 +02:00
. notifier_add = notifier_add_irq ,
. notifier_del = notifier_del_irq ,
2008-10-13 23:12:48 +00:00
. notifier_hangup = notifier_hangup_irq ,
2007-07-17 18:37:06 -07:00
} ;
2010-09-02 16:17:06 +01:00
static int dom0_read_console ( uint32_t vtermno , char * buf , int len )
{
return HYPERVISOR_console_io ( CONSOLEIO_read , len , buf ) ;
}
/*
* Either for a dom0 to write to the system console , or a domU with a
* debug version of Xen
*/
static int dom0_write_console ( uint32_t vtermno , const char * str , int len )
{
int rc = HYPERVISOR_console_io ( CONSOLEIO_write , len , ( char * ) str ) ;
if ( rc < 0 )
2013-09-27 17:18:13 -04:00
return rc ;
2010-09-02 16:17:06 +01:00
return len ;
}
static struct hv_ops dom0_hvc_ops = {
. get_chars = dom0_read_console ,
. put_chars = dom0_write_console ,
. notifier_add = notifier_add_irq ,
. notifier_del = notifier_del_irq ,
. notifier_hangup = notifier_hangup_irq ,
} ;
2012-01-27 18:31:36 +00:00
static int xen_hvm_console_init ( void )
{
int r ;
uint64_t v = 0 ;
2015-08-07 17:34:40 +01:00
unsigned long gfn ;
2012-01-30 16:02:31 +00:00
struct xencons_info * info ;
2012-01-27 18:31:36 +00:00
if ( ! xen_hvm_domain ( ) )
return - ENODEV ;
2012-01-30 16:02:31 +00:00
info = vtermno_to_xencons ( HVC_COOKIE ) ;
if ( ! info ) {
2013-08-29 14:08:18 -07:00
info = kzalloc ( sizeof ( struct xencons_info ) , GFP_KERNEL ) ;
2012-01-30 16:02:31 +00:00
if ( ! info )
return - ENOMEM ;
2012-06-26 09:30:51 -04:00
} else if ( info - > intf ! = NULL ) {
/* already configured */
2012-01-30 16:02:31 +00:00
return 0 ;
2012-06-26 09:30:51 -04:00
}
2012-05-23 12:56:59 -04:00
/*
* If the toolstack ( or the hypervisor ) hasn ' t set these values , the
2015-08-07 17:34:40 +01:00
* default value is 0. Even though gfn = 0 and evtchn = 0 are
2012-05-23 12:56:59 -04:00
* theoretically correct values , in practice they never are and they
* mean that a legacy toolstack hasn ' t initialized the pv console correctly .
*/
2012-01-27 18:31:36 +00:00
r = hvm_get_parameter ( HVM_PARAM_CONSOLE_EVTCHN , & v ) ;
2012-05-23 12:56:59 -04:00
if ( r < 0 | | v = = 0 )
2012-05-23 12:53:11 -04:00
goto err ;
2012-01-30 16:02:31 +00:00
info - > evtchn = v ;
2012-05-23 12:55:38 -04:00
v = 0 ;
r = hvm_get_parameter ( HVM_PARAM_CONSOLE_PFN , & v ) ;
2012-05-23 12:56:59 -04:00
if ( r < 0 | | v = = 0 )
2012-05-23 12:53:11 -04:00
goto err ;
2015-08-07 17:34:40 +01:00
gfn = v ;
2015-05-05 16:58:43 +01:00
info - > intf = xen_remap ( gfn < < XEN_PAGE_SHIFT , XEN_PAGE_SIZE ) ;
2012-05-23 12:53:11 -04:00
if ( info - > intf = = NULL )
goto err ;
2012-01-30 16:02:31 +00:00
info - > vtermno = HVC_COOKIE ;
spin_lock ( & xencons_lock ) ;
list_add_tail ( & info - > list , & xenconsoles ) ;
spin_unlock ( & xencons_lock ) ;
return 0 ;
2012-05-23 12:53:11 -04:00
err :
kfree ( info ) ;
return - ENODEV ;
2012-01-30 16:02:31 +00:00
}
static int xen_pv_console_init ( void )
{
struct xencons_info * info ;
if ( ! xen_pv_domain ( ) )
return - ENODEV ;
if ( ! xen_start_info - > console . domU . evtchn )
return - ENODEV ;
info = vtermno_to_xencons ( HVC_COOKIE ) ;
if ( ! info ) {
2013-08-29 14:08:18 -07:00
info = kzalloc ( sizeof ( struct xencons_info ) , GFP_KERNEL ) ;
2012-01-30 16:02:31 +00:00
if ( ! info )
return - ENOMEM ;
2012-06-26 09:30:51 -04:00
} else if ( info - > intf ! = NULL ) {
/* already configured */
2012-01-30 16:02:31 +00:00
return 0 ;
2012-06-26 09:30:51 -04:00
}
2012-01-30 16:02:31 +00:00
info - > evtchn = xen_start_info - > console . domU . evtchn ;
2015-08-07 17:34:37 +01:00
/* GFN == MFN for PV guest */
info - > intf = gfn_to_virt ( xen_start_info - > console . domU . mfn ) ;
2012-01-30 16:02:31 +00:00
info - > vtermno = HVC_COOKIE ;
spin_lock ( & xencons_lock ) ;
list_add_tail ( & info - > list , & xenconsoles ) ;
spin_unlock ( & xencons_lock ) ;
return 0 ;
}
static int xen_initial_domain_console_init ( void )
{
struct xencons_info * info ;
if ( ! xen_initial_domain ( ) )
return - ENODEV ;
info = vtermno_to_xencons ( HVC_COOKIE ) ;
if ( ! info ) {
2013-08-29 14:08:18 -07:00
info = kzalloc ( sizeof ( struct xencons_info ) , GFP_KERNEL ) ;
2012-01-30 16:02:31 +00:00
if ( ! info )
return - ENOMEM ;
}
2015-05-19 18:40:49 +01:00
info - > irq = bind_virq_to_irq ( VIRQ_CONSOLE , 0 , false ) ;
2012-01-30 16:02:31 +00:00
info - > vtermno = HVC_COOKIE ;
spin_lock ( & xencons_lock ) ;
list_add_tail ( & info - > list , & xenconsoles ) ;
spin_unlock ( & xencons_lock ) ;
2012-01-27 18:31:36 +00:00
return 0 ;
}
2015-04-29 17:10:14 -04:00
static void xen_console_update_evtchn ( struct xencons_info * info )
{
if ( xen_hvm_domain ( ) ) {
2015-05-28 09:28:22 +01:00
uint64_t v = 0 ;
2015-04-29 17:10:14 -04:00
int err ;
err = hvm_get_parameter ( HVM_PARAM_CONSOLE_EVTCHN , & v ) ;
if ( ! err & & v )
info - > evtchn = v ;
} else
info - > evtchn = xen_start_info - > console . domU . evtchn ;
}
2012-01-30 16:02:31 +00:00
void xen_console_resume ( void )
{
struct xencons_info * info = vtermno_to_xencons ( HVC_COOKIE ) ;
2015-04-29 17:10:14 -04:00
if ( info ! = NULL & & info - > irq ) {
if ( ! xen_initial_domain ( ) )
xen_console_update_evtchn ( info ) ;
2012-01-30 16:02:31 +00:00
rebind_evtchn_irq ( info - > evtchn , info - > irq ) ;
2015-04-29 17:10:14 -04:00
}
2012-01-30 16:02:31 +00:00
}
static void xencons_disconnect_backend ( struct xencons_info * info )
{
if ( info - > irq > 0 )
unbind_from_irqhandler ( info - > irq , NULL ) ;
info - > irq = 0 ;
if ( info - > evtchn > 0 )
xenbus_free_evtchn ( info - > xbdev , info - > evtchn ) ;
info - > evtchn = 0 ;
if ( info - > gntref > 0 )
gnttab_free_grant_references ( info - > gntref ) ;
info - > gntref = 0 ;
if ( info - > hvc ! = NULL )
hvc_remove ( info - > hvc ) ;
info - > hvc = NULL ;
}
static void xencons_free ( struct xencons_info * info )
{
free_page ( ( unsigned long ) info - > intf ) ;
info - > intf = NULL ;
info - > vtermno = 0 ;
kfree ( info ) ;
}
static int xen_console_remove ( struct xencons_info * info )
{
xencons_disconnect_backend ( info ) ;
spin_lock ( & xencons_lock ) ;
list_del ( & info - > list ) ;
spin_unlock ( & xencons_lock ) ;
if ( info - > xbdev ! = NULL )
xencons_free ( info ) ;
else {
if ( xen_hvm_domain ( ) )
iounmap ( info - > intf ) ;
kfree ( info ) ;
2010-09-02 16:17:06 +01:00
}
2012-01-30 16:02:31 +00:00
return 0 ;
}
2008-05-26 23:31:25 +01:00
2012-02-21 11:30:42 +00:00
# ifdef CONFIG_HVC_XEN_FRONTEND
2012-01-30 16:02:31 +00:00
static int xencons_remove ( struct xenbus_device * dev )
{
return xen_console_remove ( dev_get_drvdata ( & dev - > dev ) ) ;
}
2007-07-17 18:37:06 -07:00
2012-01-30 16:02:31 +00:00
static int xencons_connect_backend ( struct xenbus_device * dev ,
struct xencons_info * info )
{
int ret , evtchn , devid , ref , irq ;
struct xenbus_transaction xbt ;
grant_ref_t gref_head ;
ret = xenbus_alloc_evtchn ( dev , & evtchn ) ;
if ( ret )
return ret ;
info - > evtchn = evtchn ;
irq = bind_evtchn_to_irq ( evtchn ) ;
if ( irq < 0 )
return irq ;
info - > irq = irq ;
devid = dev - > nodename [ strlen ( dev - > nodename ) - 1 ] - ' 0 ' ;
info - > hvc = hvc_alloc ( xenbus_devid_to_vtermno ( devid ) ,
irq , & domU_hvc_ops , 256 ) ;
if ( IS_ERR ( info - > hvc ) )
return PTR_ERR ( info - > hvc ) ;
ret = gnttab_alloc_grant_references ( 1 , & gref_head ) ;
if ( ret < 0 )
return ret ;
info - > gntref = gref_head ;
ref = gnttab_claim_grant_reference ( & gref_head ) ;
if ( ref < 0 )
return ref ;
gnttab_grant_foreign_access_ref ( ref , info - > xbdev - > otherend_id ,
2015-08-07 17:34:40 +01:00
virt_to_gfn ( info - > intf ) , 0 ) ;
2012-01-30 16:02:31 +00:00
again :
ret = xenbus_transaction_start ( & xbt ) ;
if ( ret ) {
xenbus_dev_fatal ( dev , ret , " starting transaction " ) ;
return ret ;
}
ret = xenbus_printf ( xbt , dev - > nodename , " ring-ref " , " %d " , ref ) ;
if ( ret )
goto error_xenbus ;
ret = xenbus_printf ( xbt , dev - > nodename , " port " , " %u " ,
evtchn ) ;
if ( ret )
goto error_xenbus ;
ret = xenbus_transaction_end ( xbt , 0 ) ;
if ( ret ) {
if ( ret = = - EAGAIN )
goto again ;
xenbus_dev_fatal ( dev , ret , " completing transaction " ) ;
return ret ;
}
2008-05-26 23:31:25 +01:00
2012-01-30 16:02:31 +00:00
xenbus_switch_state ( dev , XenbusStateInitialised ) ;
2007-07-17 18:37:06 -07:00
return 0 ;
2012-01-30 16:02:31 +00:00
error_xenbus :
xenbus_transaction_end ( xbt , 1 ) ;
xenbus_dev_fatal ( dev , ret , " writing xenstore " ) ;
return ret ;
2007-07-17 18:37:06 -07:00
}
2012-11-19 13:21:50 -05:00
static int xencons_probe ( struct xenbus_device * dev ,
2012-01-30 16:02:31 +00:00
const struct xenbus_device_id * id )
2008-05-26 23:31:25 +01:00
{
2012-01-30 16:02:31 +00:00
int ret , devid ;
struct xencons_info * info ;
devid = dev - > nodename [ strlen ( dev - > nodename ) - 1 ] - ' 0 ' ;
if ( devid = = 0 )
return - ENODEV ;
2012-05-15 11:47:47 +03:00
info = kzalloc ( sizeof ( struct xencons_info ) , GFP_KERNEL ) ;
2012-01-30 16:02:31 +00:00
if ( ! info )
2012-05-15 11:47:47 +03:00
return - ENOMEM ;
2012-01-30 16:02:31 +00:00
dev_set_drvdata ( & dev - > dev , info ) ;
info - > xbdev = dev ;
info - > vtermno = xenbus_devid_to_vtermno ( devid ) ;
info - > intf = ( void * ) __get_free_page ( GFP_KERNEL | __GFP_ZERO ) ;
if ( ! info - > intf )
goto error_nomem ;
ret = xencons_connect_backend ( dev , info ) ;
if ( ret < 0 )
goto error ;
spin_lock ( & xencons_lock ) ;
list_add_tail ( & info - > list , & xenconsoles ) ;
spin_unlock ( & xencons_lock ) ;
return 0 ;
error_nomem :
ret = - ENOMEM ;
xenbus_dev_fatal ( dev , ret , " allocating device memory " ) ;
error :
xencons_disconnect_backend ( info ) ;
xencons_free ( info ) ;
return ret ;
}
static int xencons_resume ( struct xenbus_device * dev )
{
struct xencons_info * info = dev_get_drvdata ( & dev - > dev ) ;
xencons_disconnect_backend ( info ) ;
2015-05-05 16:58:43 +01:00
memset ( info - > intf , 0 , XEN_PAGE_SIZE ) ;
2012-01-30 16:02:31 +00:00
return xencons_connect_backend ( dev , info ) ;
2008-05-26 23:31:25 +01:00
}
2012-01-30 16:02:31 +00:00
static void xencons_backend_changed ( struct xenbus_device * dev ,
enum xenbus_state backend_state )
{
switch ( backend_state ) {
case XenbusStateReconfiguring :
case XenbusStateReconfigured :
case XenbusStateInitialising :
case XenbusStateInitialised :
case XenbusStateUnknown :
break ;
case XenbusStateInitWait :
break ;
case XenbusStateConnected :
xenbus_switch_state ( dev , XenbusStateConnected ) ;
break ;
2012-09-21 17:04:24 +01:00
case XenbusStateClosed :
if ( dev - > state = = XenbusStateClosed )
break ;
/* Missed the backend's CLOSING state -- fallthrough */
2012-01-30 16:02:31 +00:00
case XenbusStateClosing :
xenbus_frontend_closed ( dev ) ;
break ;
}
}
static const struct xenbus_device_id xencons_ids [ ] = {
{ " console " } ,
{ " " }
} ;
2014-09-08 17:30:41 +01:00
static struct xenbus_driver xencons_driver = {
. name = " xenconsole " ,
. ids = xencons_ids ,
2012-02-21 11:30:42 +00:00
. probe = xencons_probe ,
. remove = xencons_remove ,
. resume = xencons_resume ,
. otherend_changed = xencons_backend_changed ,
2014-09-08 17:30:41 +01:00
} ;
2012-02-21 11:30:42 +00:00
# endif /* CONFIG_HVC_XEN_FRONTEND */
static int __init xen_hvc_init ( void )
{
int r ;
struct xencons_info * info ;
const struct hv_ops * ops ;
if ( ! xen_domain ( ) )
return - ENODEV ;
if ( xen_initial_domain ( ) ) {
ops = & dom0_hvc_ops ;
r = xen_initial_domain_console_init ( ) ;
if ( r < 0 )
return r ;
info = vtermno_to_xencons ( HVC_COOKIE ) ;
} else {
ops = & domU_hvc_ops ;
if ( xen_hvm_domain ( ) )
r = xen_hvm_console_init ( ) ;
else
r = xen_pv_console_init ( ) ;
if ( r < 0 )
return r ;
info = vtermno_to_xencons ( HVC_COOKIE ) ;
info - > irq = bind_evtchn_to_irq ( info - > evtchn ) ;
}
if ( info - > irq < 0 )
info - > irq = 0 ; /* NO_IRQ */
else
irq_set_noprobe ( info - > irq ) ;
info - > hvc = hvc_alloc ( HVC_COOKIE , info - > irq , ops , 256 ) ;
if ( IS_ERR ( info - > hvc ) ) {
r = PTR_ERR ( info - > hvc ) ;
spin_lock ( & xencons_lock ) ;
list_del ( & info - > list ) ;
spin_unlock ( & xencons_lock ) ;
if ( info - > irq )
unbind_from_irqhandler ( info - > irq , NULL ) ;
kfree ( info ) ;
return r ;
}
r = 0 ;
# ifdef CONFIG_HVC_XEN_FRONTEND
r = xenbus_register_frontend ( & xencons_driver ) ;
# endif
return r ;
}
2014-01-15 16:35:43 -05:00
device_initcall ( xen_hvc_init ) ;
2007-07-17 18:37:06 -07:00
static int xen_cons_init ( void )
{
2012-01-27 18:31:36 +00:00
const struct hv_ops * ops ;
2010-09-02 16:17:06 +01:00
2012-01-27 18:31:36 +00:00
if ( ! xen_domain ( ) )
2007-07-17 18:37:06 -07:00
return 0 ;
2010-09-02 16:17:06 +01:00
if ( xen_initial_domain ( ) )
ops = & dom0_hvc_ops ;
2012-01-27 18:31:36 +00:00
else {
2012-01-30 16:02:31 +00:00
int r ;
2010-09-02 16:17:06 +01:00
ops = & domU_hvc_ops ;
2012-01-30 16:02:31 +00:00
if ( xen_hvm_domain ( ) )
r = xen_hvm_console_init ( ) ;
2012-01-27 18:31:36 +00:00
else
2012-01-30 16:02:31 +00:00
r = xen_pv_console_init ( ) ;
if ( r < 0 )
return r ;
2012-01-27 18:31:36 +00:00
}
2010-09-02 16:17:06 +01:00
hvc_instantiate ( HVC_COOKIE , 0 , ops ) ;
2007-07-17 18:37:06 -07:00
return 0 ;
}
console_initcall ( xen_cons_init ) ;
2008-05-26 23:31:00 +01:00
# ifdef CONFIG_EARLY_PRINTK
2007-07-17 18:37:06 -07:00
static void xenboot_write_console ( struct console * console , const char * string ,
unsigned len )
{
unsigned int linelen , off = 0 ;
const char * pos ;
2012-01-27 18:31:36 +00:00
if ( ! xen_pv_domain ( ) )
return ;
2010-09-02 16:17:06 +01:00
dom0_write_console ( 0 , string , len ) ;
if ( xen_initial_domain ( ) )
return ;
2008-05-26 23:31:00 +01:00
2010-09-02 16:17:06 +01:00
domU_write_console ( 0 , " (early) " , 8 ) ;
2007-07-17 18:37:06 -07:00
while ( off < len & & NULL ! = ( pos = strchr ( string + off , ' \n ' ) ) ) {
linelen = pos - string + off ;
if ( off + linelen > len )
break ;
2010-09-02 16:17:06 +01:00
domU_write_console ( 0 , string + off , linelen ) ;
domU_write_console ( 0 , " \r \n " , 2 ) ;
2007-07-17 18:37:06 -07:00
off + = linelen + 1 ;
}
if ( off < len )
2010-09-02 16:17:06 +01:00
domU_write_console ( 0 , string + off , len - off ) ;
2007-07-17 18:37:06 -07:00
}
struct console xenboot_console = {
. name = " xenboot " ,
. write = xenboot_write_console ,
2008-05-26 23:31:00 +01:00
. flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME ,
2013-10-01 19:00:49 +01:00
. index = - 1 ,
2007-07-17 18:37:06 -07:00
} ;
2008-05-26 23:31:00 +01:00
# endif /* CONFIG_EARLY_PRINTK */
2008-05-26 23:30:59 +01:00
void xen_raw_console_write ( const char * str )
{
2013-09-27 17:18:13 -04:00
ssize_t len = strlen ( str ) ;
int rc = 0 ;
if ( xen_domain ( ) ) {
rc = dom0_write_console ( 0 , str , len ) ;
# ifdef CONFIG_X86
if ( rc = = - ENOSYS & & xen_hvm_domain ( ) )
goto outb_print ;
} else if ( xen_cpuid_base ( ) ) {
int i ;
outb_print :
for ( i = 0 ; i < len ; i + + )
outb ( str [ i ] , 0xe9 ) ;
# endif
}
2008-05-26 23:30:59 +01:00
}
void xen_raw_printk ( const char * fmt , . . . )
{
static char buf [ 512 ] ;
va_list ap ;
va_start ( ap , fmt ) ;
vsnprintf ( buf , sizeof ( buf ) , fmt , ap ) ;
va_end ( ap ) ;
xen_raw_console_write ( buf ) ;
}