2009-07-31 02:03:45 +04:00
/*P:600
* The x86 architecture has segments , which involve a table of descriptors
2007-07-26 21:41:02 +04:00
* which can be used to do funky things with virtual address interpretation .
* We originally used to use segments so the Guest couldn ' t alter the
* Guest < - > Host Switcher , and then we had to trim Guest segments , and restore
* for userspace per - thread segments , but trim again for on userspace - > kernel
* transitions . . . This nightmarish creation was contained within this file ,
* where we knew not to tread without heavy armament and a change of underwear .
*
* In these modern times , the segment handling code consists of simple sanity
* checks , and the worst you ' ll experience reading this code is butterfly - rash
2009-07-31 02:03:45 +04:00
* from frolicking through its parklike serenity .
: */
2007-07-19 12:49:23 +04:00
# include "lg.h"
2007-07-26 21:41:04 +04:00
/*H:600
* Segments & The Global Descriptor Table
*
* ( That title sounds like a bad Nerdcore group . Not to suggest that there are
* any good Nerdcore groups , but in high school a friend of mine had a band
* called Joe Fish and the Chips , so there are definitely worse band names ) .
*
* To refresh : the GDT is a table of 8 - byte values describing segments . Once
* set up , these segments can be loaded into one of the 6 " segment registers " .
*
* GDT entries are passed around as " struct desc_struct " s , which like IDT
* entries are split into two 32 - bit members , " a " and " b " . One day , someone
* will clean that up , and be declared a Hero . ( No pressure , I ' m just saying ) .
*
* Anyway , the GDT entry contains a base ( the start address of the segment ) , a
* limit ( the size of the segment - 1 ) , and some flags . Sounds simple , and it
* would be , except those zany Intel engineers decided that it was too boring
* to put the base at one end , the limit at the other , and the flags in
* between . They decided to shotgun the bits at random throughout the 8 bytes ,
* like so :
*
* 0 16 40 48 52 56 63
* [ limit part 1 ] [ base part 1 ] [ flags ] [ li ] [ fl ] [ base ]
* mit ags part 2
* part 2
*
* As a result , this file contains a certain amount of magic numeracy . Let ' s
* begin .
*/
2009-07-31 02:03:45 +04:00
/*
* There are several entries we don ' t let the Guest set . The TSS entry is the
2007-07-26 21:41:04 +04:00
* " Task State Segment " which controls all kinds of delicate things . The
* LGUEST_CS and LGUEST_DS entries are reserved for the Switcher , and the
2009-07-31 02:03:45 +04:00
* the Guest can ' t be trusted to deal with double faults .
*/
2009-03-18 19:38:35 +03:00
static bool ignored_gdt ( unsigned int num )
2007-07-19 12:49:23 +04:00
{
return ( num = = GDT_ENTRY_TSS
| | num = = GDT_ENTRY_LGUEST_CS
| | num = = GDT_ENTRY_LGUEST_DS
| | num = = GDT_ENTRY_DOUBLEFAULT_TSS ) ;
}
2009-07-31 02:03:45 +04:00
/*H:630
* Once the Guest gave us new GDT entries , we fix them up a little . We
2007-08-09 14:57:13 +04:00
* don ' t care if they ' re invalid : the worst that can happen is a General
* Protection Fault in the Switcher when it restores a Guest segment register
* which tries to use that entry . Then we kill the Guest for causing such a
2009-07-31 02:03:45 +04:00
* mess : the message will be " unhandled trap 256 " .
*/
2008-01-07 16:05:33 +03:00
static void fixup_gdt_table ( struct lg_cpu * cpu , unsigned start , unsigned end )
2007-07-19 12:49:23 +04:00
{
unsigned int i ;
for ( i = start ; i < end ; i + + ) {
2009-07-31 02:03:45 +04:00
/*
* We never copy these ones to real GDT , so we don ' t care what
* they say
*/
2007-07-19 12:49:23 +04:00
if ( ignored_gdt ( i ) )
continue ;
2009-07-31 02:03:45 +04:00
/*
* Segment descriptors contain a privilege level : the Guest is
2007-07-26 21:41:04 +04:00
* sometimes careless and leaves this as 0 , even though it ' s
2009-07-31 02:03:45 +04:00
* running at privilege level 1. If so , we fix it here .
*/
2012-01-12 09:14:47 +04:00
if ( cpu - > arch . gdt [ i ] . dpl = = 0 )
cpu - > arch . gdt [ i ] . dpl | = GUEST_PL ;
2007-07-19 12:49:23 +04:00
2009-07-31 02:03:45 +04:00
/*
* Each descriptor has an " accessed " bit . If we don ' t set it
2007-07-26 21:41:04 +04:00
* now , the CPU will try to set it when the Guest first loads
* that entry into a segment register . But the GDT isn ' t
2009-07-31 02:03:45 +04:00
* writable by the Guest , so bad things can happen .
*/
2012-01-12 09:14:47 +04:00
cpu - > arch . gdt [ i ] . type | = 0x1 ;
2007-07-19 12:49:23 +04:00
}
}
2009-07-31 02:03:45 +04:00
/*H:610
* Like the IDT , we never simply use the GDT the Guest gives us . We keep
2007-10-25 09:02:50 +04:00
* a GDT for each CPU , and copy across the Guest ' s entries each time we want to
* run the Guest on that CPU .
*
* This routine is called at boot or modprobe time for each CPU to set up the
* constant GDT entries : the ones which are the same no matter what Guest we ' re
2009-07-31 02:03:45 +04:00
* running .
*/
2007-07-19 12:49:23 +04:00
void setup_default_gdt_entries ( struct lguest_ro_state * state )
{
struct desc_struct * gdt = state - > guest_gdt ;
unsigned long tss = ( unsigned long ) & state - > guest_tss ;
2007-10-25 09:02:50 +04:00
/* The Switcher segments are full 0-4G segments, privilege level 0 */
2007-07-19 12:49:23 +04:00
gdt [ GDT_ENTRY_LGUEST_CS ] = FULL_EXEC_SEGMENT ;
gdt [ GDT_ENTRY_LGUEST_DS ] = FULL_SEGMENT ;
2009-07-31 02:03:45 +04:00
/*
* The TSS segment refers to the TSS entry for this particular CPU .
*/
2012-01-12 09:14:47 +04:00
gdt [ GDT_ENTRY_TSS ] . a = 0 ;
gdt [ GDT_ENTRY_TSS ] . b = 0 ;
gdt [ GDT_ENTRY_TSS ] . limit0 = 0x67 ;
gdt [ GDT_ENTRY_TSS ] . base0 = tss & 0xFFFF ;
gdt [ GDT_ENTRY_TSS ] . base1 = ( tss > > 16 ) & 0xFF ;
gdt [ GDT_ENTRY_TSS ] . base2 = tss > > 24 ;
gdt [ GDT_ENTRY_TSS ] . type = 0x9 ; /* 32-bit TSS (available) */
gdt [ GDT_ENTRY_TSS ] . p = 0x1 ; /* Entry is present */
gdt [ GDT_ENTRY_TSS ] . dpl = 0x0 ; /* Privilege level 0 */
gdt [ GDT_ENTRY_TSS ] . s = 0x0 ; /* system segment */
2007-07-19 12:49:23 +04:00
}
2009-07-31 02:03:45 +04:00
/*
* This routine sets up the initial Guest GDT for booting . All entries start
* as 0 ( unusable ) .
*/
2008-01-07 16:05:33 +03:00
void setup_guest_gdt ( struct lg_cpu * cpu )
2007-07-19 12:49:23 +04:00
{
2009-07-31 02:03:45 +04:00
/*
* Start with full 0 - 4 G segments . . . except the Guest is allowed to use
* them , so set the privilege level appropriately in the flags .
*/
2008-01-07 16:05:33 +03:00
cpu - > arch . gdt [ GDT_ENTRY_KERNEL_CS ] = FULL_EXEC_SEGMENT ;
cpu - > arch . gdt [ GDT_ENTRY_KERNEL_DS ] = FULL_SEGMENT ;
2012-01-12 09:14:47 +04:00
cpu - > arch . gdt [ GDT_ENTRY_KERNEL_CS ] . dpl | = GUEST_PL ;
cpu - > arch . gdt [ GDT_ENTRY_KERNEL_DS ] . dpl | = GUEST_PL ;
2007-07-19 12:49:23 +04:00
}
2009-07-31 02:03:45 +04:00
/*H:650
* An optimization of copy_gdt ( ) , for just the three " thead-local storage "
* entries .
*/
2008-01-07 16:05:33 +03:00
void copy_gdt_tls ( const struct lg_cpu * cpu , struct desc_struct * gdt )
2007-07-19 12:49:23 +04:00
{
unsigned int i ;
for ( i = GDT_ENTRY_TLS_MIN ; i < = GDT_ENTRY_TLS_MAX ; i + + )
2008-01-07 16:05:33 +03:00
gdt [ i ] = cpu - > arch . gdt [ i ] ;
2007-07-19 12:49:23 +04:00
}
2009-07-31 02:03:45 +04:00
/*H:640
* When the Guest is run on a different CPU , or the GDT entries have changed ,
* copy_gdt ( ) is called to copy the Guest ' s GDT entries across to this CPU ' s
* GDT .
*/
2008-01-07 16:05:33 +03:00
void copy_gdt ( const struct lg_cpu * cpu , struct desc_struct * gdt )
2007-07-19 12:49:23 +04:00
{
unsigned int i ;
2009-07-31 02:03:45 +04:00
/*
* The default entries from setup_default_gdt_entries ( ) are not
* replaced . See ignored_gdt ( ) above .
*/
2007-07-19 12:49:23 +04:00
for ( i = 0 ; i < GDT_ENTRIES ; i + + )
if ( ! ignored_gdt ( i ) )
2008-01-07 16:05:33 +03:00
gdt [ i ] = cpu - > arch . gdt [ i ] ;
2007-07-19 12:49:23 +04:00
}
2009-07-31 02:03:45 +04:00
/*H:620
* This is where the Guest asks us to load a new GDT entry
* ( LHCALL_LOAD_GDT_ENTRY ) . We tweak the entry and copy it in .
*/
2009-04-20 09:14:00 +04:00
void load_guest_gdt_entry ( struct lg_cpu * cpu , u32 num , u32 lo , u32 hi )
2007-07-19 12:49:23 +04:00
{
2009-07-31 02:03:45 +04:00
/*
* We assume the Guest has the same number of GDT entries as the
* Host , otherwise we ' d have to dynamically allocate the Guest GDT .
*/
2010-01-04 11:56:14 +03:00
if ( num > = ARRAY_SIZE ( cpu - > arch . gdt ) ) {
2008-01-18 00:19:42 +03:00
kill_guest ( cpu , " too many gdt entries %i " , num ) ;
2010-01-04 11:56:14 +03:00
return ;
}
2007-07-19 12:49:23 +04:00
2009-04-20 09:14:00 +04:00
/* Set it up, then fix it. */
cpu - > arch . gdt [ num ] . a = lo ;
cpu - > arch . gdt [ num ] . b = hi ;
fixup_gdt_table ( cpu , num , num + 1 ) ;
2009-07-31 02:03:45 +04:00
/*
* Mark that the GDT changed so the core knows it has to copy it again ,
* even if the Guest is run on the same CPU .
*/
2008-01-18 00:14:46 +03:00
cpu - > changed | = CHANGED_GDT ;
2007-07-19 12:49:23 +04:00
}
2009-07-31 02:03:45 +04:00
/*
* This is the fast - track version for just changing the three TLS entries .
2007-10-25 09:02:50 +04:00
* Remember that this happens on every context switch , so it ' s worth
* optimizing . But wouldn ' t it be neater to have a single hypercall to cover
2009-07-31 02:03:45 +04:00
* both cases ?
*/
2008-01-07 16:05:33 +03:00
void guest_load_tls ( struct lg_cpu * cpu , unsigned long gtls )
2007-07-19 12:49:23 +04:00
{
2008-01-07 16:05:33 +03:00
struct desc_struct * tls = & cpu - > arch . gdt [ GDT_ENTRY_TLS_MIN ] ;
2007-07-19 12:49:23 +04:00
2008-01-18 00:19:42 +03:00
__lgread ( cpu , tls , gtls , sizeof ( * tls ) * GDT_ENTRY_TLS_ENTRIES ) ;
2008-01-07 16:05:33 +03:00
fixup_gdt_table ( cpu , GDT_ENTRY_TLS_MIN , GDT_ENTRY_TLS_MAX + 1 ) ;
2007-10-25 09:02:50 +04:00
/* Note that just the TLS entries have changed. */
2008-01-18 00:14:46 +03:00
cpu - > changed | = CHANGED_GDT_TLS ;
2007-07-19 12:49:23 +04:00
}
2007-07-26 21:41:04 +04:00
2007-10-25 09:02:50 +04:00
/*H:660
2007-07-26 21:41:04 +04:00
* With this , we have finished the Host .
*
* Five of the seven parts of our task are complete . You have made it through
* the Bit of Despair ( I think that ' s somewhere in the page table code ,
* myself ) .
*
* Next , we examine " make Switcher " . It ' s short , but intense .
*/