segments.c 7.78 KB
Newer Older
Rusty Russell's avatar
Rusty Russell committed
1 2
/*P:600
 * The x86 architecture has segments, which involve a table of descriptors
3 4 5 6 7 8 9 10 11
 * 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
Rusty Russell's avatar
Rusty Russell committed
12 13
 * from frolicking through its parklike serenity.
:*/
Rusty Russell's avatar
Rusty Russell committed
14 15
#include "lg.h"

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
/*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.
 */

Rusty Russell's avatar
Rusty Russell committed
46 47
/*
 * There are several entries we don't let the Guest set.  The TSS entry is the
48 49
 * "Task State Segment" which controls all kinds of delicate things.  The
 * LGUEST_CS and LGUEST_DS entries are reserved for the Switcher, and the
Rusty Russell's avatar
Rusty Russell committed
50 51
 * the Guest can't be trusted to deal with double faults.
 */
52
static bool ignored_gdt(unsigned int num)
Rusty Russell's avatar
Rusty Russell committed
53 54 55 56 57 58 59
{
	return (num == GDT_ENTRY_TSS
		|| num == GDT_ENTRY_LGUEST_CS
		|| num == GDT_ENTRY_LGUEST_DS
		|| num == GDT_ENTRY_DOUBLEFAULT_TSS);
}

Rusty Russell's avatar
Rusty Russell committed
60 61
/*H:630
 * Once the Guest gave us new GDT entries, we fix them up a little.  We
62 63 64
 * 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
Rusty Russell's avatar
Rusty Russell committed
65 66
 * mess: the message will be "unhandled trap 256".
 */
67
static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end)
Rusty Russell's avatar
Rusty Russell committed
68 69 70 71
{
	unsigned int i;

	for (i = start; i < end; i++) {
Rusty Russell's avatar
Rusty Russell committed
72 73 74 75
		/*
		 * We never copy these ones to real GDT, so we don't care what
		 * they say
		 */
Rusty Russell's avatar
Rusty Russell committed
76 77 78
		if (ignored_gdt(i))
			continue;

Rusty Russell's avatar
Rusty Russell committed
79 80
		/*
		 * Segment descriptors contain a privilege level: the Guest is
81
		 * sometimes careless and leaves this as 0, even though it's
Rusty Russell's avatar
Rusty Russell committed
82 83
		 * running at privilege level 1.  If so, we fix it here.
		 */
84 85
		if (cpu->arch.gdt[i].dpl == 0)
			cpu->arch.gdt[i].dpl |= GUEST_PL;
Rusty Russell's avatar
Rusty Russell committed
86

Rusty Russell's avatar
Rusty Russell committed
87 88
		/*
		 * Each descriptor has an "accessed" bit.  If we don't set it
89 90
		 * now, the CPU will try to set it when the Guest first loads
		 * that entry into a segment register.  But the GDT isn't
Rusty Russell's avatar
Rusty Russell committed
91 92
		 * writable by the Guest, so bad things can happen.
		 */
93
		cpu->arch.gdt[i].type |= 0x1;
Rusty Russell's avatar
Rusty Russell committed
94 95 96
	}
}

Rusty Russell's avatar
Rusty Russell committed
97 98
/*H:610
 * Like the IDT, we never simply use the GDT the Guest gives us.  We keep
Rusty Russell's avatar
Rusty Russell committed
99 100 101 102 103
 * 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
Rusty Russell's avatar
Rusty Russell committed
104 105
 * running.
 */
Rusty Russell's avatar
Rusty Russell committed
106 107 108 109 110
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;

Rusty Russell's avatar
Rusty Russell committed
111
	/* The Switcher segments are full 0-4G segments, privilege level 0 */
Rusty Russell's avatar
Rusty Russell committed
112 113 114
	gdt[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
	gdt[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;

Rusty Russell's avatar
Rusty Russell committed
115 116 117
	/*
	 * The TSS segment refers to the TSS entry for this particular CPU.
	 */
118 119 120 121 122 123 124 125 126 127 128 129
	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 */

Rusty Russell's avatar
Rusty Russell committed
130 131
}

Rusty Russell's avatar
Rusty Russell committed
132 133 134 135
/*
 * This routine sets up the initial Guest GDT for booting.  All entries start
 * as 0 (unusable).
 */
136
void setup_guest_gdt(struct lg_cpu *cpu)
Rusty Russell's avatar
Rusty Russell committed
137
{
Rusty Russell's avatar
Rusty Russell committed
138 139 140 141
	/*
	 * Start with full 0-4G segments...except the Guest is allowed to use
	 * them, so set the privilege level appropriately in the flags.
	 */
142 143
	cpu->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
	cpu->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
144 145
	cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].dpl |= GUEST_PL;
	cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].dpl |= GUEST_PL;
Rusty Russell's avatar
Rusty Russell committed
146 147
}

Rusty Russell's avatar
Rusty Russell committed
148 149 150 151
/*H:650
 * An optimization of copy_gdt(), for just the three "thead-local storage"
 * entries.
 */
152
void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt)
Rusty Russell's avatar
Rusty Russell committed
153 154 155 156
{
	unsigned int i;

	for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
157
		gdt[i] = cpu->arch.gdt[i];
Rusty Russell's avatar
Rusty Russell committed
158 159
}

Rusty Russell's avatar
Rusty Russell committed
160 161 162 163 164
/*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.
 */
165
void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt)
Rusty Russell's avatar
Rusty Russell committed
166 167 168
{
	unsigned int i;

Rusty Russell's avatar
Rusty Russell committed
169 170 171 172
	/*
	 * The default entries from setup_default_gdt_entries() are not
	 * replaced.  See ignored_gdt() above.
	 */
Rusty Russell's avatar
Rusty Russell committed
173 174
	for (i = 0; i < GDT_ENTRIES; i++)
		if (!ignored_gdt(i))
175
			gdt[i] = cpu->arch.gdt[i];
Rusty Russell's avatar
Rusty Russell committed
176 177
}

Rusty Russell's avatar
Rusty Russell committed
178 179 180 181
/*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.
 */
182
void load_guest_gdt_entry(struct lg_cpu *cpu, u32 num, u32 lo, u32 hi)
Rusty Russell's avatar
Rusty Russell committed
183
{
Rusty Russell's avatar
Rusty Russell committed
184 185 186 187
	/*
	 * We assume the Guest has the same number of GDT entries as the
	 * Host, otherwise we'd have to dynamically allocate the Guest GDT.
	 */
188
	if (num >= ARRAY_SIZE(cpu->arch.gdt)) {
189
		kill_guest(cpu, "too many gdt entries %i", num);
190 191
		return;
	}
Rusty Russell's avatar
Rusty Russell committed
192

193 194 195 196
	/* 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);
Rusty Russell's avatar
Rusty Russell committed
197 198 199 200
	/*
	 * 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.
	 */
201
	cpu->changed |= CHANGED_GDT;
Rusty Russell's avatar
Rusty Russell committed
202 203
}

Rusty Russell's avatar
Rusty Russell committed
204 205
/*
 * This is the fast-track version for just changing the three TLS entries.
Rusty Russell's avatar
Rusty Russell committed
206 207
 * 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
Rusty Russell's avatar
Rusty Russell committed
208 209
 * both cases?
 */
210
void guest_load_tls(struct lg_cpu *cpu, unsigned long gtls)
Rusty Russell's avatar
Rusty Russell committed
211
{
212
	struct desc_struct *tls = &cpu->arch.gdt[GDT_ENTRY_TLS_MIN];
Rusty Russell's avatar
Rusty Russell committed
213

214
	__lgread(cpu, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
215
	fixup_gdt_table(cpu, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
Rusty Russell's avatar
Rusty Russell committed
216
	/* Note that just the TLS entries have changed. */
217
	cpu->changed |= CHANGED_GDT_TLS;
Rusty Russell's avatar
Rusty Russell committed
218
}
219

Rusty Russell's avatar
Rusty Russell committed
220
/*H:660
221 222 223 224 225 226 227 228
 * 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.
 */