2009-07-31 02:03:45 +04:00
/*P:500
* Just as userspace programs request kernel operations through a system
2007-07-26 21:41:02 +04:00
* call , the Guest requests Host operations through a " hypercall " . You might
* notice this nomenclature doesn ' t really follow any logic , but the name has
* been around for long enough that we ' re stuck with it . As you ' d expect , this
2009-07-31 02:03:45 +04:00
* code is basically a one big switch statement .
: */
2007-07-26 21:41:02 +04:00
/* Copyright (C) 2006 Rusty Russell IBM Corporation
2007-07-19 12:49:23 +04:00
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 . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <linux/uaccess.h>
# include <linux/syscalls.h>
# include <linux/mm.h>
2008-01-19 04:59:07 +03:00
# include <linux/ktime.h>
2007-07-19 12:49:23 +04:00
# include <asm/page.h>
# include <asm/pgtable.h>
# include "lg.h"
2009-07-31 02:03:45 +04:00
/*H:120
* This is the core hypercall routine : where the Guest gets what it wants .
* Or gets killed . Or , in the case of LHCALL_SHUTDOWN , both .
*/
2008-01-07 16:05:27 +03:00
static void do_hcall ( struct lg_cpu * cpu , struct hcall_args * args )
2007-07-19 12:49:23 +04:00
{
2007-10-22 05:03:31 +04:00
switch ( args - > arg0 ) {
2007-07-19 12:49:23 +04:00
case LHCALL_FLUSH_ASYNC :
2009-07-31 02:03:45 +04:00
/*
* This call does nothing , except by breaking out of the Guest
* it makes us process all the asynchronous hypercalls .
*/
2007-07-19 12:49:23 +04:00
break ;
2009-06-13 08:27:02 +04:00
case LHCALL_SEND_INTERRUPTS :
2009-07-31 02:03:45 +04:00
/*
* This call does nothing too , but by breaking out of the Guest
* it makes us process any pending interrupts .
*/
2009-06-13 08:27:02 +04:00
break ;
2007-07-19 12:49:23 +04:00
case LHCALL_LGUEST_INIT :
2009-07-31 02:03:45 +04:00
/*
* You can ' t get here unless you ' re already initialized . Don ' t
* do that .
*/
2008-01-18 00:19:42 +03:00
kill_guest ( cpu , " already have lguest_data " ) ;
2007-07-19 12:49:23 +04:00
break ;
2007-12-28 11:56:24 +03:00
case LHCALL_SHUTDOWN : {
2007-07-19 12:49:23 +04:00
char msg [ 128 ] ;
2009-07-31 02:03:45 +04:00
/*
2009-07-31 02:03:45 +04:00
* Shutdown is such a trivial hypercall that we do it in five
2009-07-31 02:03:45 +04:00
* lines right here .
*
* If the lgread fails , it will call kill_guest ( ) itself ; the
* kill_guest ( ) with the message will be ignored .
*/
2008-01-18 00:19:42 +03:00
__lgread ( cpu , msg , args - > arg1 , sizeof ( msg ) ) ;
2007-07-19 12:49:23 +04:00
msg [ sizeof ( msg ) - 1 ] = ' \0 ' ;
2008-01-18 00:19:42 +03:00
kill_guest ( cpu , " CRASH: %s " , msg ) ;
2007-12-28 11:56:24 +03:00
if ( args - > arg2 = = LGUEST_SHUTDOWN_RESTART )
2008-01-18 00:19:42 +03:00
cpu - > lg - > dead = ERR_PTR ( - ERESTART ) ;
2007-07-19 12:49:23 +04:00
break ;
}
case LHCALL_FLUSH_TLB :
2009-07-31 02:03:45 +04:00
/* FLUSH_TLB comes in two flavors, depending on the argument: */
2007-10-22 05:03:31 +04:00
if ( args - > arg1 )
2008-01-07 16:05:35 +03:00
guest_pagetable_clear_all ( cpu ) ;
2007-07-19 12:49:23 +04:00
else
2008-01-07 16:05:37 +03:00
guest_pagetable_flush_user ( cpu ) ;
2007-07-19 12:49:23 +04:00
break ;
2007-07-26 21:41:04 +04:00
2009-07-31 02:03:45 +04:00
/*
* All these calls simply pass the arguments through to the right
* routines .
*/
2007-07-19 12:49:23 +04:00
case LHCALL_NEW_PGTABLE :
2008-01-07 16:05:35 +03:00
guest_new_pagetable ( cpu , args - > arg1 ) ;
2007-07-19 12:49:23 +04:00
break ;
case LHCALL_SET_STACK :
2008-01-07 16:05:35 +03:00
guest_set_stack ( cpu , args - > arg1 , args - > arg2 , args - > arg3 ) ;
2007-07-19 12:49:23 +04:00
break ;
case LHCALL_SET_PTE :
2009-06-13 08:27:07 +04:00
# ifdef CONFIG_X86_PAE
guest_set_pte ( cpu , args - > arg1 , args - > arg2 ,
__pte ( args - > arg3 | ( u64 ) args - > arg4 < < 32 ) ) ;
# else
2008-01-18 00:19:42 +03:00
guest_set_pte ( cpu , args - > arg1 , args - > arg2 , __pte ( args - > arg3 ) ) ;
2009-06-13 08:27:07 +04:00
# endif
2007-07-19 12:49:23 +04:00
break ;
2009-05-30 22:48:08 +04:00
case LHCALL_SET_PGD :
guest_set_pgd ( cpu - > lg , args - > arg1 , args - > arg2 ) ;
2007-07-19 12:49:23 +04:00
break ;
2009-06-13 08:27:07 +04:00
# ifdef CONFIG_X86_PAE
case LHCALL_SET_PMD :
guest_set_pmd ( cpu - > lg , args - > arg1 , args - > arg2 ) ;
break ;
# endif
2007-07-19 12:49:23 +04:00
case LHCALL_SET_CLOCKEVENT :
2008-01-07 16:05:28 +03:00
guest_set_clockevent ( cpu , args - > arg1 ) ;
2007-07-19 12:49:23 +04:00
break ;
case LHCALL_TS :
2007-07-26 21:41:04 +04:00
/* This sets the TS flag, as we saw used in run_guest(). */
2008-01-07 16:05:35 +03:00
cpu - > ts = args - > arg1 ;
2007-07-19 12:49:23 +04:00
break ;
case LHCALL_HALT :
2007-07-26 21:41:04 +04:00
/* Similarly, this sets the halted flag for run_guest(). */
2008-01-07 16:05:34 +03:00
cpu - > halted = 1 ;
2007-07-19 12:49:23 +04:00
break ;
2007-10-22 05:24:10 +04:00
case LHCALL_NOTIFY :
2008-01-07 16:05:36 +03:00
cpu - > pending_notify = args - > arg1 ;
2007-10-22 05:24:10 +04:00
break ;
2007-07-19 12:49:23 +04:00
default :
2007-10-25 09:02:50 +04:00
/* It should be an architecture-specific hypercall. */
2008-01-07 16:05:27 +03:00
if ( lguest_arch_do_hcall ( cpu , args ) )
2008-01-18 00:19:42 +03:00
kill_guest ( cpu , " Bad hypercall %li \n " , args - > arg0 ) ;
2007-07-19 12:49:23 +04:00
}
}
2009-07-31 02:03:45 +04:00
/*H:124
* Asynchronous hypercalls are easy : we just look in the array in the
2007-10-22 05:03:31 +04:00
* Guest ' s " struct lguest_data " to see if any new ones are marked " ready " .
2007-07-26 21:41:04 +04:00
*
* We are careful to do these in order : obviously we respect the order the
* Guest put them in the ring , but we also promise the Guest that they will
* happen before any normal hypercall ( which is why we check this before
2009-07-31 02:03:45 +04:00
* checking for a normal hcall ) .
*/
2008-01-07 16:05:27 +03:00
static void do_async_hcalls ( struct lg_cpu * cpu )
2007-07-19 12:49:23 +04:00
{
unsigned int i ;
u8 st [ LHCALL_RING_SIZE ] ;
2007-07-26 21:41:04 +04:00
/* For simplicity, we copy the entire call status array in at once. */
2008-01-18 00:19:42 +03:00
if ( copy_from_user ( & st , & cpu - > lg - > lguest_data - > hcall_status , sizeof ( st ) ) )
2007-07-19 12:49:23 +04:00
return ;
2007-07-26 21:41:04 +04:00
/* We process "struct lguest_data"s hcalls[] ring once. */
2007-07-19 12:49:23 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( st ) ; i + + ) {
2007-10-22 05:03:31 +04:00
struct hcall_args args ;
2009-07-31 02:03:45 +04:00
/*
* We remember where we were up to from last time . This makes
2007-07-26 21:41:04 +04:00
* sure that the hypercalls are done in the order the Guest
2009-07-31 02:03:45 +04:00
* places them in the ring .
*/
2008-01-07 16:05:27 +03:00
unsigned int n = cpu - > next_hcall ;
2007-07-19 12:49:23 +04:00
2007-07-26 21:41:04 +04:00
/* 0xFF means there's no call here (yet). */
2007-07-19 12:49:23 +04:00
if ( st [ n ] = = 0xFF )
break ;
2009-07-31 02:03:45 +04:00
/*
* OK , we have hypercall . Increment the " next_hcall " cursor ,
* and wrap back to 0 if we reach the end .
*/
2008-01-07 16:05:27 +03:00
if ( + + cpu - > next_hcall = = LHCALL_RING_SIZE )
cpu - > next_hcall = 0 ;
2007-07-19 12:49:23 +04:00
2009-07-31 02:03:45 +04:00
/*
* Copy the hypercall arguments into a local copy of the
* hcall_args struct .
*/
2008-01-18 00:19:42 +03:00
if ( copy_from_user ( & args , & cpu - > lg - > lguest_data - > hcalls [ n ] ,
2007-10-22 05:03:31 +04:00
sizeof ( struct hcall_args ) ) ) {
2008-01-18 00:19:42 +03:00
kill_guest ( cpu , " Fetching async hypercalls " ) ;
2007-07-19 12:49:23 +04:00
break ;
}
2007-07-26 21:41:04 +04:00
/* Do the hypercall, same as a normal one. */
2008-01-07 16:05:27 +03:00
do_hcall ( cpu , & args ) ;
2007-07-26 21:41:04 +04:00
/* Mark the hypercall done. */
2008-01-18 00:19:42 +03:00
if ( put_user ( 0xFF , & cpu - > lg - > lguest_data - > hcall_status [ n ] ) ) {
kill_guest ( cpu , " Writing result for async hypercall " ) ;
2007-07-19 12:49:23 +04:00
break ;
}
2009-07-31 02:03:45 +04:00
/*
* Stop doing hypercalls if they want to notify the Launcher :
* it needs to service this first .
*/
2008-01-07 16:05:36 +03:00
if ( cpu - > pending_notify )
2007-07-19 12:49:23 +04:00
break ;
}
}
2009-07-31 02:03:45 +04:00
/*
* Last of all , we look at what happens first of all . The very first time the
* Guest makes a hypercall , we end up here to set things up :
*/
2008-01-07 16:05:27 +03:00
static void initialize ( struct lg_cpu * cpu )
2007-07-19 12:49:23 +04:00
{
2009-07-31 02:03:45 +04:00
/*
* You can ' t do anything until you ' re initialized . The Guest knows the
* rules , so we ' re unforgiving here .
*/
2008-01-07 16:05:27 +03:00
if ( cpu - > hcall - > arg0 ! = LHCALL_LGUEST_INIT ) {
2008-01-18 00:19:42 +03:00
kill_guest ( cpu , " hypercall %li before INIT " , cpu - > hcall - > arg0 ) ;
2007-07-19 12:49:23 +04:00
return ;
}
2008-01-07 16:05:27 +03:00
if ( lguest_arch_init_hypercalls ( cpu ) )
2008-01-18 00:19:42 +03:00
kill_guest ( cpu , " bad guest page %p " , cpu - > lg - > lguest_data ) ;
2007-10-22 05:03:26 +04:00
2009-07-31 02:03:45 +04:00
/*
* The Guest tells us where we ' re not to deliver interrupts by putting
* the range of addresses into " struct lguest_data " .
*/
2008-01-18 00:19:42 +03:00
if ( get_user ( cpu - > lg - > noirq_start , & cpu - > lg - > lguest_data - > noirq_start )
| | get_user ( cpu - > lg - > noirq_end , & cpu - > lg - > lguest_data - > noirq_end ) )
kill_guest ( cpu , " bad guest page %p " , cpu - > lg - > lguest_data ) ;
2007-07-19 12:49:23 +04:00
2009-07-31 02:03:45 +04:00
/*
* We write the current time into the Guest ' s data page once so it can
* set its clock .
*/
2008-01-18 00:19:42 +03:00
write_timestamp ( cpu ) ;
2007-07-27 07:42:52 +04:00
2007-10-22 05:03:36 +04:00
/* page_tables.c will also do some setup. */
2008-01-18 00:19:42 +03:00
page_table_guest_data_init ( cpu ) ;
2007-10-22 05:03:36 +04:00
2009-07-31 02:03:45 +04:00
/*
* This is the one case where the above accesses might have been the
2007-07-26 21:41:04 +04:00
* first write to a Guest page . This may have caused a copy - on - write
2007-10-25 09:02:50 +04:00
* fault , but the old page might be ( read - only ) in the Guest
2009-07-31 02:03:45 +04:00
* pagetable .
*/
2008-01-07 16:05:35 +03:00
guest_pagetable_clear_all ( cpu ) ;
2007-07-19 12:49:23 +04:00
}
2008-03-28 19:05:53 +03:00
/*:*/
2009-07-31 02:03:45 +04:00
/*M:013
* If a Guest reads from a page ( so creates a mapping ) that it has never
2008-03-28 19:05:53 +03:00
* written to , and then the Launcher writes to it ( ie . the output of a virtual
* device ) , the Guest will still see the old page . In practice , this never
* happens : why would the Guest read a page which it has never written to ? But
2009-07-31 02:03:45 +04:00
* a similar scenario might one day bite us , so it ' s worth mentioning .
2009-07-31 02:03:45 +04:00
*
* Note that if we used a shared anonymous mapping in the Launcher instead of
* mapping / dev / zero private , we wouldn ' t worry about cop - on - write . And we
* need that to switch the Launcher to processes ( away from threads ) anyway .
2009-07-31 02:03:45 +04:00
: */
2007-07-19 12:49:23 +04:00
2007-07-26 21:41:04 +04:00
/*H:100
* Hypercalls
*
* Remember from the Guest , hypercalls come in two flavors : normal and
* asynchronous . This file handles both of types .
*/
2008-01-07 16:05:27 +03:00
void do_hypercalls ( struct lg_cpu * cpu )
2007-07-19 12:49:23 +04:00
{
2007-10-22 05:03:30 +04:00
/* Not initialized yet? This hypercall must do it. */
2008-01-07 16:05:27 +03:00
if ( unlikely ( ! cpu - > lg - > lguest_data ) ) {
2007-10-22 05:03:30 +04:00
/* Set up the "struct lguest_data" */
2008-01-07 16:05:27 +03:00
initialize ( cpu ) ;
2007-10-22 05:03:30 +04:00
/* Hcall is done. */
2008-01-07 16:05:27 +03:00
cpu - > hcall = NULL ;
2007-07-19 12:49:23 +04:00
return ;
}
2009-07-31 02:03:45 +04:00
/*
* The Guest has initialized .
2007-07-26 21:41:04 +04:00
*
2009-07-31 02:03:45 +04:00
* Look in the hypercall ring for the async hypercalls :
*/
2008-01-07 16:05:27 +03:00
do_async_hcalls ( cpu ) ;
2007-07-26 21:41:04 +04:00
2009-07-31 02:03:45 +04:00
/*
* If we stopped reading the hypercall ring because the Guest did a
2007-10-22 05:24:10 +04:00
* NOTIFY to the Launcher , we want to return now . Otherwise we do
2009-07-31 02:03:45 +04:00
* the hypercall .
*/
2008-01-07 16:05:36 +03:00
if ( ! cpu - > pending_notify ) {
2008-01-07 16:05:27 +03:00
do_hcall ( cpu , cpu - > hcall ) ;
2009-07-31 02:03:45 +04:00
/*
* Tricky point : we reset the hcall pointer to mark the
2007-10-22 05:03:30 +04:00
* hypercall as " done " . We use the hcall pointer rather than
* the trap number to indicate a hypercall is pending .
* Normally it doesn ' t matter : the Guest will run again and
* update the trap number before we come back here .
*
2007-10-25 09:02:50 +04:00
* However , if we are signalled or the Guest sends I / O to the
2007-10-22 05:03:30 +04:00
* Launcher , the run_guest ( ) loop will exit without running the
* Guest . When it comes back it would try to re - run the
2009-07-31 02:03:45 +04:00
* hypercall . Finding that bug sucked .
*/
2008-01-07 16:05:27 +03:00
cpu - > hcall = NULL ;
2007-07-19 12:49:23 +04:00
}
}
2007-07-27 07:42:52 +04:00
2009-07-31 02:03:45 +04:00
/*
* This routine supplies the Guest with time : it ' s used for wallclock time at
* initial boot and as a rough time source if the TSC isn ' t available .
*/
2008-01-18 00:19:42 +03:00
void write_timestamp ( struct lg_cpu * cpu )
2007-07-27 07:42:52 +04:00
{
struct timespec now ;
ktime_get_real_ts ( & now ) ;
2008-01-18 00:19:42 +03:00
if ( copy_to_user ( & cpu - > lg - > lguest_data - > time ,
& now , sizeof ( struct timespec ) ) )
kill_guest ( cpu , " Writing timestamp " ) ;
2007-07-27 07:42:52 +04:00
}