2012-09-14 17:53:39 +04:00
# include <xen/xen.h>
2012-09-14 17:37:32 +04:00
# include <xen/events.h>
2012-09-13 16:06:52 +04:00
# include <xen/grant_table.h>
# include <xen/hvm.h>
2013-04-25 20:17:04 +04:00
# include <xen/interface/vcpu.h>
2012-09-14 17:53:39 +04:00
# include <xen/interface/xen.h>
# include <xen/interface/memory.h>
2012-09-13 16:06:52 +04:00
# include <xen/interface/hvm/params.h>
2012-08-08 21:20:18 +04:00
# include <xen/features.h>
2012-09-14 17:53:39 +04:00
# include <xen/platform_pci.h>
2012-09-13 16:06:52 +04:00
# include <xen/xenbus.h>
2012-10-03 15:28:26 +04:00
# include <xen/page.h>
2013-04-25 14:23:07 +04:00
# include <xen/interface/sched.h>
2012-10-03 19:37:09 +04:00
# include <xen/xen-ops.h>
2015-11-23 13:35:12 +03:00
# include <asm/paravirt.h>
2012-09-14 17:53:39 +04:00
# include <asm/xen/hypervisor.h>
# include <asm/xen/hypercall.h>
2013-04-25 14:23:07 +04:00
# include <asm/system_misc.h>
2012-09-14 17:37:32 +04:00
# include <linux/interrupt.h>
# include <linux/irqreturn.h>
2012-09-14 17:53:39 +04:00
# include <linux/module.h>
2012-09-14 14:47:52 +04:00
# include <linux/of.h>
# include <linux/of_irq.h>
# include <linux/of_address.h>
2013-09-09 15:35:26 +04:00
# include <linux/cpuidle.h>
# include <linux/cpufreq.h>
2014-01-30 16:52:59 +04:00
# include <linux/cpu.h>
2015-05-06 17:14:22 +03:00
# include <linux/console.h>
2015-11-23 13:41:12 +03:00
# include <linux/pvclock_gtod.h>
# include <linux/time64.h>
2015-11-23 13:40:12 +03:00
# include <linux/timekeeping.h>
2015-11-23 13:41:12 +03:00
# include <linux/timekeeper_internal.h>
2012-09-14 17:53:39 +04:00
2012-10-03 19:37:09 +04:00
# include <linux/mm.h>
2012-09-14 17:53:39 +04:00
struct start_info _xen_start_info ;
struct start_info * xen_start_info = & _xen_start_info ;
2014-12-21 23:30:58 +03:00
EXPORT_SYMBOL ( xen_start_info ) ;
2012-09-14 17:53:39 +04:00
enum xen_domain_type xen_domain_type = XEN_NATIVE ;
2014-12-21 23:30:58 +03:00
EXPORT_SYMBOL ( xen_domain_type ) ;
2012-09-14 17:53:39 +04:00
struct shared_info xen_dummy_shared_info ;
struct shared_info * HYPERVISOR_shared_info = ( void * ) & xen_dummy_shared_info ;
DEFINE_PER_CPU ( struct vcpu_info * , xen_vcpu ) ;
2013-04-25 20:17:04 +04:00
static struct vcpu_info __percpu * xen_vcpu_info ;
2012-09-14 17:53:39 +04:00
2012-10-03 15:28:26 +04:00
/* These are unused until we support booting "pre-ballooned" */
unsigned long xen_released_pages ;
struct xen_memory_region xen_extra_mem [ XEN_EXTRA_MEM_MAX_REGIONS ] __initdata ;
2015-05-06 17:09:06 +03:00
static __read_mostly unsigned int xen_events_irq ;
2012-09-14 17:37:32 +04:00
2015-05-06 17:13:31 +03:00
static __initdata struct device_node * xen_node ;
2015-08-07 19:34:41 +03:00
int xen_remap_domain_gfn_array ( struct vm_area_struct * vma ,
2012-09-14 17:53:39 +04:00
unsigned long addr ,
2015-08-07 19:34:41 +03:00
xen_pfn_t * gfn , int nr ,
2015-03-11 17:49:57 +03:00
int * err_ptr , pgprot_t prot ,
unsigned domid ,
2012-10-03 19:37:09 +04:00
struct page * * pages )
2012-09-14 17:53:39 +04:00
{
2015-08-07 19:34:41 +03:00
return xen_xlate_remap_gfn_array ( vma , addr , gfn , nr , err_ptr ,
2015-03-11 17:49:56 +03:00
prot , domid , pages ) ;
2012-09-14 17:53:39 +04:00
}
2015-08-07 19:34:41 +03:00
EXPORT_SYMBOL_GPL ( xen_remap_domain_gfn_array ) ;
2015-03-11 17:49:57 +03:00
/* Not used by XENFEAT_auto_translated guests. */
2015-08-07 19:34:41 +03:00
int xen_remap_domain_gfn_range ( struct vm_area_struct * vma ,
2015-03-11 17:49:57 +03:00
unsigned long addr ,
2015-08-07 19:34:41 +03:00
xen_pfn_t gfn , int nr ,
2015-03-11 17:49:57 +03:00
pgprot_t prot , unsigned domid ,
struct page * * pages )
{
return - ENOSYS ;
}
2015-08-07 19:34:41 +03:00
EXPORT_SYMBOL_GPL ( xen_remap_domain_gfn_range ) ;
2012-09-14 14:47:52 +04:00
2015-08-07 19:34:41 +03:00
int xen_unmap_domain_gfn_range ( struct vm_area_struct * vma ,
2012-10-03 19:37:09 +04:00
int nr , struct page * * pages )
{
2015-03-11 17:49:56 +03:00
return xen_xlate_unmap_gfn_range ( vma , nr , pages ) ;
2012-10-03 19:37:09 +04:00
}
2015-08-07 19:34:41 +03:00
EXPORT_SYMBOL_GPL ( xen_unmap_domain_gfn_range ) ;
2012-10-03 19:37:09 +04:00
2015-11-23 13:35:12 +03:00
static unsigned long long xen_stolen_accounting ( int cpu )
{
struct vcpu_runstate_info state ;
BUG_ON ( cpu ! = smp_processor_id ( ) ) ;
xen_get_runstate_snapshot ( & state ) ;
WARN_ON ( state . state ! = RUNSTATE_running ) ;
return state . time [ RUNSTATE_runnable ] + state . time [ RUNSTATE_offline ] ;
}
2015-11-23 13:40:12 +03:00
static void xen_read_wallclock ( struct timespec64 * ts )
{
u32 version ;
struct timespec64 now , ts_monotonic ;
struct shared_info * s = HYPERVISOR_shared_info ;
struct pvclock_wall_clock * wall_clock = & ( s - > wc ) ;
/* get wallclock at system boot */
do {
version = wall_clock - > version ;
rmb ( ) ; /* fetch version before time */
now . tv_sec = ( ( uint64_t ) wall_clock - > sec_hi < < 32 ) | wall_clock - > sec ;
now . tv_nsec = wall_clock - > nsec ;
rmb ( ) ; /* fetch time before checking version */
} while ( ( wall_clock - > version & 1 ) | | ( version ! = wall_clock - > version ) ) ;
/* time since system boot */
ktime_get_ts64 ( & ts_monotonic ) ;
* ts = timespec64_add ( now , ts_monotonic ) ;
}
2015-11-23 13:41:12 +03:00
static int xen_pvclock_gtod_notify ( struct notifier_block * nb ,
unsigned long was_set , void * priv )
{
/* Protected by the calling core code serialization */
static struct timespec64 next_sync ;
struct xen_platform_op op ;
struct timespec64 now , system_time ;
struct timekeeper * tk = priv ;
now . tv_sec = tk - > xtime_sec ;
now . tv_nsec = ( long ) ( tk - > tkr_mono . xtime_nsec > > tk - > tkr_mono . shift ) ;
system_time = timespec64_add ( now , tk - > wall_to_monotonic ) ;
/*
* We only take the expensive HV call when the clock was set
* or when the 11 minutes RTC synchronization time elapsed .
*/
if ( ! was_set & & timespec64_compare ( & now , & next_sync ) < 0 )
return NOTIFY_OK ;
op . cmd = XENPF_settime64 ;
op . u . settime64 . mbz = 0 ;
op . u . settime64 . secs = now . tv_sec ;
op . u . settime64 . nsecs = now . tv_nsec ;
op . u . settime64 . system_time = timespec64_to_ns ( & system_time ) ;
( void ) HYPERVISOR_platform_op ( & op ) ;
/*
* Move the next drift compensation time 11 minutes
* ahead . That ' s emulating the sync_cmos_clock ( ) update for
* the hardware RTC .
*/
next_sync = now ;
next_sync . tv_sec + = 11 * 60 ;
return NOTIFY_OK ;
}
static struct notifier_block xen_pvclock_gtod_notifier = {
. notifier_call = xen_pvclock_gtod_notify ,
} ;
2014-01-30 16:52:59 +04:00
static void xen_percpu_init ( void )
2013-04-25 20:17:04 +04:00
{
struct vcpu_register_vcpu_info info ;
struct vcpu_info * vcpup ;
int err ;
2013-05-08 15:59:01 +04:00
int cpu = get_cpu ( ) ;
2013-04-25 20:17:04 +04:00
2015-10-22 19:22:46 +03:00
/*
* VCPUOP_register_vcpu_info cannot be called twice for the same
* vcpu , so if vcpu_info is already registered , just get out . This
* can happen with cpu - hotplug .
*/
if ( per_cpu ( xen_vcpu , cpu ) ! = NULL )
goto after_register_vcpu_info ;
2013-04-25 20:17:04 +04:00
pr_info ( " Xen: initializing cpu%d \n " , cpu ) ;
vcpup = per_cpu_ptr ( xen_vcpu_info , cpu ) ;
2015-05-05 18:36:56 +03:00
info . mfn = virt_to_gfn ( vcpup ) ;
info . offset = xen_offset_in_page ( vcpup ) ;
2013-04-25 20:17:04 +04:00
err = HYPERVISOR_vcpu_op ( VCPUOP_register_vcpu_info , cpu , & info ) ;
2013-05-08 17:02:38 +04:00
BUG_ON ( err ) ;
per_cpu ( xen_vcpu , cpu ) = vcpup ;
2015-11-23 13:35:12 +03:00
xen_setup_runstate_info ( cpu ) ;
2015-10-22 19:22:46 +03:00
after_register_vcpu_info :
2013-05-08 15:59:01 +04:00
enable_percpu_irq ( xen_events_irq , 0 ) ;
2013-07-29 20:06:05 +04:00
put_cpu ( ) ;
2013-04-25 20:17:04 +04:00
}
2013-07-21 19:17:54 +04:00
static void xen_restart ( enum reboot_mode reboot_mode , const char * cmd )
2013-04-25 14:23:07 +04:00
{
struct sched_shutdown r = { . reason = SHUTDOWN_reboot } ;
int rc ;
rc = HYPERVISOR_sched_op ( SCHEDOP_shutdown , & r ) ;
2014-07-25 20:05:39 +04:00
BUG_ON ( rc ) ;
2013-04-25 14:23:07 +04:00
}
static void xen_power_off ( void )
{
struct sched_shutdown r = { . reason = SHUTDOWN_poweroff } ;
int rc ;
rc = HYPERVISOR_sched_op ( SCHEDOP_shutdown , & r ) ;
2014-07-25 20:05:39 +04:00
BUG_ON ( rc ) ;
2013-04-25 14:23:07 +04:00
}
2014-01-30 16:52:59 +04:00
static int xen_cpu_notification ( struct notifier_block * self ,
unsigned long action ,
void * hcpu )
{
switch ( action ) {
case CPU_STARTING :
xen_percpu_init ( ) ;
break ;
2015-10-22 19:22:46 +03:00
case CPU_DYING :
disable_percpu_irq ( xen_events_irq ) ;
break ;
2014-01-30 16:52:59 +04:00
default :
break ;
}
return NOTIFY_OK ;
}
static struct notifier_block xen_cpu_notifier = {
. notifier_call = xen_cpu_notification ,
} ;
static irqreturn_t xen_arm_callback ( int irq , void * arg )
{
xen_hvm_evtchn_do_upcall ( ) ;
return IRQ_HANDLED ;
}
2012-09-14 14:47:52 +04:00
/*
* see Documentation / devicetree / bindings / arm / xen . txt for the
* documentation of the Xen Device Tree format .
*/
2012-09-13 16:06:52 +04:00
# define GRANT_TABLE_PHYSADDR 0
2015-05-06 17:13:31 +03:00
void __init xen_early_init ( void )
2012-09-14 14:47:52 +04:00
{
int len ;
const char * s = NULL ;
const char * version = NULL ;
const char * xen_prefix = " xen,xen- " ;
2015-05-06 17:13:31 +03:00
xen_node = of_find_compatible_node ( NULL , NULL , " xen,xen " ) ;
if ( ! xen_node ) {
2012-09-14 14:47:52 +04:00
pr_debug ( " No Xen support \n " ) ;
2015-05-06 17:13:31 +03:00
return ;
2012-09-14 14:47:52 +04:00
}
2015-05-06 17:13:31 +03:00
s = of_get_property ( xen_node , " compatible " , & len ) ;
2012-09-14 14:47:52 +04:00
if ( strlen ( xen_prefix ) + 3 < len & &
! strncmp ( xen_prefix , s , strlen ( xen_prefix ) ) )
version = s + strlen ( xen_prefix ) ;
if ( version = = NULL ) {
pr_debug ( " Xen version not found \n " ) ;
2015-05-06 17:13:31 +03:00
return ;
2015-05-06 17:09:06 +03:00
}
2015-05-06 17:13:31 +03:00
pr_info ( " Xen %s support found \n " , version ) ;
2014-01-30 16:52:59 +04:00
2012-09-14 14:47:52 +04:00
xen_domain_type = XEN_HVM_DOMAIN ;
2012-08-08 21:20:18 +04:00
xen_setup_features ( ) ;
2014-09-11 02:49:30 +04:00
2012-08-08 21:20:18 +04:00
if ( xen_feature ( XENFEAT_dom0 ) )
xen_start_info - > flags | = SIF_INITDOMAIN | SIF_PRIVILEGED ;
else
xen_start_info - > flags & = ~ ( SIF_INITDOMAIN | SIF_PRIVILEGED ) ;
2015-05-06 17:14:22 +03:00
if ( ! console_set_on_cmdline & & ! xen_initial_domain ( ) )
add_preferred_console ( " hvc " , 0 , NULL ) ;
2015-05-06 17:13:31 +03:00
}
static int __init xen_guest_init ( void )
{
struct xen_add_to_physmap xatp ;
struct shared_info * shared_info_page = NULL ;
struct resource res ;
phys_addr_t grant_frames ;
if ( ! xen_domain ( ) )
return 0 ;
if ( of_address_to_resource ( xen_node , GRANT_TABLE_PHYSADDR , & res ) ) {
pr_err ( " Xen grant table base address not found \n " ) ;
return - ENODEV ;
}
grant_frames = res . start ;
xen_events_irq = irq_of_parse_and_map ( xen_node , 0 ) ;
if ( ! xen_events_irq ) {
pr_err ( " Xen event channel interrupt not found \n " ) ;
return - ENODEV ;
}
shared_info_page = ( struct shared_info * ) get_zeroed_page ( GFP_KERNEL ) ;
2012-08-08 21:20:18 +04:00
2012-09-14 14:47:52 +04:00
if ( ! shared_info_page ) {
pr_err ( " not enough memory \n " ) ;
return - ENOMEM ;
}
xatp . domid = DOMID_SELF ;
xatp . idx = 0 ;
xatp . space = XENMAPSPACE_shared_info ;
2015-05-05 18:36:56 +03:00
xatp . gpfn = virt_to_gfn ( shared_info_page ) ;
2012-09-14 14:47:52 +04:00
if ( HYPERVISOR_memory_op ( XENMEM_add_to_physmap , & xatp ) )
BUG ( ) ;
HYPERVISOR_shared_info = ( struct shared_info * ) shared_info_page ;
/* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
* page , we use it in the event channel upcall and in some pvclock
2013-04-25 20:17:04 +04:00
* related functions .
2012-09-14 14:47:52 +04:00
* The shared info contains exactly 1 CPU ( the boot CPU ) . The guest
* is required to use VCPUOP_register_vcpu_info to place vcpu info
2013-04-25 20:17:04 +04:00
* for secondary CPUs as they are brought up .
* For uniformity we use VCPUOP_register_vcpu_info even on cpu0 .
*/
xen_vcpu_info = __alloc_percpu ( sizeof ( struct vcpu_info ) ,
sizeof ( struct vcpu_info ) ) ;
if ( xen_vcpu_info = = NULL )
return - ENOMEM ;
2012-09-13 16:06:52 +04:00
2014-01-06 19:40:36 +04:00
if ( gnttab_setup_auto_xlat_frames ( grant_frames ) ) {
free_percpu ( xen_vcpu_info ) ;
return - ENOMEM ;
}
2012-09-13 16:06:52 +04:00
gnttab_init ( ) ;
if ( ! xen_initial_domain ( ) )
xenbus_probe ( NULL ) ;
2013-09-09 15:35:26 +04:00
/*
* Making sure board specific code will not set up ops for
* cpu idle and cpu freq .
*/
disable_cpuidle ( ) ;
disable_cpufreq ( ) ;
2014-01-30 16:52:59 +04:00
xen_init_IRQ ( ) ;
if ( request_percpu_irq ( xen_events_irq , xen_arm_callback ,
" events " , & xen_vcpu ) ) {
pr_err ( " Error request IRQ %d \n " , xen_events_irq ) ;
return - EINVAL ;
}
xen_percpu_init ( ) ;
register_cpu_notifier ( & xen_cpu_notifier ) ;
2015-11-23 13:35:12 +03:00
pv_time_ops . steal_clock = xen_stolen_accounting ;
static_key_slow_inc ( & paravirt_steal_enabled ) ;
2015-11-23 13:41:12 +03:00
if ( xen_initial_domain ( ) )
pvclock_gtod_register_notifier ( & xen_pvclock_gtod_notifier ) ;
2015-11-23 13:35:12 +03:00
2013-05-08 15:59:01 +04:00
return 0 ;
}
2014-01-30 16:52:59 +04:00
early_initcall ( xen_guest_init ) ;
2013-05-08 15:59:01 +04:00
static int __init xen_pm_init ( void )
{
2013-08-29 16:43:52 +04:00
if ( ! xen_domain ( ) )
return - ENODEV ;
2013-04-25 14:23:07 +04:00
pm_power_off = xen_power_off ;
arm_pm_restart = xen_restart ;
2015-11-23 13:40:12 +03:00
if ( ! xen_initial_domain ( ) ) {
struct timespec64 ts ;
xen_read_wallclock ( & ts ) ;
do_settimeofday64 ( & ts ) ;
}
2013-04-25 14:23:07 +04:00
2012-09-14 14:47:52 +04:00
return 0 ;
}
2013-08-29 16:43:52 +04:00
late_initcall ( xen_pm_init ) ;
2012-09-14 17:37:32 +04:00
2014-05-08 19:54:02 +04:00
/* empty stubs */
void xen_arch_pre_suspend ( void ) { }
void xen_arch_post_suspend ( int suspend_cancelled ) { }
void xen_timer_resume ( void ) { }
void xen_arch_resume ( void ) { }
2015-05-07 19:55:23 +03:00
void xen_arch_suspend ( void ) { }
2014-05-08 19:54:02 +04:00
2015-09-14 16:20:52 +03:00
/* In the hypercall.S file. */
2012-11-07 02:06:52 +04:00
EXPORT_SYMBOL_GPL ( HYPERVISOR_event_channel_op ) ;
EXPORT_SYMBOL_GPL ( HYPERVISOR_grant_table_op ) ;
2012-11-08 19:58:55 +04:00
EXPORT_SYMBOL_GPL ( HYPERVISOR_xen_version ) ;
EXPORT_SYMBOL_GPL ( HYPERVISOR_console_io ) ;
EXPORT_SYMBOL_GPL ( HYPERVISOR_sched_op ) ;
EXPORT_SYMBOL_GPL ( HYPERVISOR_hvm_op ) ;
EXPORT_SYMBOL_GPL ( HYPERVISOR_memory_op ) ;
EXPORT_SYMBOL_GPL ( HYPERVISOR_physdev_op ) ;
2013-04-25 17:53:05 +04:00
EXPORT_SYMBOL_GPL ( HYPERVISOR_vcpu_op ) ;
2013-07-02 14:42:40 +04:00
EXPORT_SYMBOL_GPL ( HYPERVISOR_tmem_op ) ;
2015-11-23 13:37:12 +03:00
EXPORT_SYMBOL_GPL ( HYPERVISOR_platform_op ) ;
2014-05-09 20:10:49 +04:00
EXPORT_SYMBOL_GPL ( HYPERVISOR_multicall ) ;
2012-11-07 02:06:52 +04:00
EXPORT_SYMBOL_GPL ( privcmd_call ) ;