summaryrefslogtreecommitdiff
path: root/i386/i386/gdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'i386/i386/gdt.c')
-rw-r--r--i386/i386/gdt.c62
1 files changed, 49 insertions, 13 deletions
diff --git a/i386/i386/gdt.c b/i386/i386/gdt.c
index fb18360e..4edd3ec5 100644
--- a/i386/i386/gdt.c
+++ b/i386/i386/gdt.c
@@ -35,10 +35,13 @@
#include <kern/assert.h>
#include <intel/pmap.h>
+#include <kern/cpu_number.h>
+#include <machine/percpu.h>
#include "vm_param.h"
#include "seg.h"
#include "gdt.h"
+#include "mp_desc.h"
#ifdef MACH_PV_DESCRIPTORS
/* It is actually defined in xen_boothdr.S */
@@ -46,37 +49,47 @@ extern
#endif /* MACH_PV_DESCRIPTORS */
struct real_descriptor gdt[GDTSZ];
-void
-gdt_init(void)
+static void
+gdt_fill(int cpu, struct real_descriptor *mygdt)
{
/* Initialize the kernel code and data segment descriptors. */
#ifdef __x86_64__
assert(LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS == 0);
- fill_gdt_descriptor(KERNEL_CS, 0, 0, ACC_PL_K|ACC_CODE_R, SZ_64);
- fill_gdt_descriptor(KERNEL_DS, 0, 0, ACC_PL_K|ACC_DATA_W, SZ_64);
+ _fill_gdt_descriptor(mygdt, KERNEL_CS, 0, 0, ACC_PL_K|ACC_CODE_R, SZ_64);
+ _fill_gdt_descriptor(mygdt, KERNEL_DS, 0, 0, ACC_PL_K|ACC_DATA_W, SZ_64);
#ifndef MACH_PV_DESCRIPTORS
- fill_gdt_descriptor(LINEAR_DS, 0, 0, ACC_PL_K|ACC_DATA_W, SZ_64);
+ _fill_gdt_descriptor(mygdt, LINEAR_DS, 0, 0, ACC_PL_K|ACC_DATA_W, SZ_64);
#endif /* MACH_PV_DESCRIPTORS */
#else
- fill_gdt_descriptor(KERNEL_CS,
+ _fill_gdt_descriptor(mygdt, KERNEL_CS,
LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
LINEAR_MAX_KERNEL_ADDRESS - (LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) - 1,
ACC_PL_K|ACC_CODE_R, SZ_32);
- fill_gdt_descriptor(KERNEL_DS,
+ _fill_gdt_descriptor(mygdt, KERNEL_DS,
LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
LINEAR_MAX_KERNEL_ADDRESS - (LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) - 1,
ACC_PL_K|ACC_DATA_W, SZ_32);
#ifndef MACH_PV_DESCRIPTORS
- fill_gdt_descriptor(LINEAR_DS,
+ _fill_gdt_descriptor(mygdt, LINEAR_DS,
0,
0xffffffff,
ACC_PL_K|ACC_DATA_W, SZ_32);
#endif /* MACH_PV_DESCRIPTORS */
+ vm_offset_t thiscpu = kvtolin(&percpu_array[cpu]);
+ _fill_gdt_descriptor(mygdt, PERCPU_DS,
+ thiscpu,
+ thiscpu + sizeof(struct percpu) - 1,
+#ifdef __x86_64__
+ ACC_PL_K|ACC_DATA_W, SZ_64
+#else
+ ACC_PL_K|ACC_DATA_W, SZ_32
+#endif
+ );
#endif
#ifdef MACH_PV_DESCRIPTORS
- unsigned long frame = kv_to_mfn(gdt);
- pmap_set_page_readonly(gdt);
+ unsigned long frame = kv_to_mfn(mygdt);
+ pmap_set_page_readonly(mygdt);
if (hyp_set_gdt(kv_to_la(&frame), GDTSZ))
panic("couldn't set gdt\n");
#endif
@@ -94,12 +107,16 @@ gdt_init(void)
{
struct pseudo_descriptor pdesc;
- pdesc.limit = sizeof(gdt)-1;
- pdesc.linear_base = kvtolin(&gdt);
+ pdesc.limit = (GDTSZ * sizeof(struct real_descriptor))-1;
+ pdesc.linear_base = kvtolin(mygdt);
lgdt(&pdesc);
}
#endif /* MACH_PV_DESCRIPTORS */
+}
+static void
+reload_segs(void)
+{
/* Reload all the segment registers from the new GDT.
We must load ds and es with 0 before loading them with KERNEL_DS
because some processors will "optimize out" the loads
@@ -114,9 +131,19 @@ gdt_init(void)
"movw %w1,%%ds\n"
"movw %w1,%%es\n"
+ "movw %w3,%%gs\n"
"movw %w1,%%ss\n"
- : : "i" (KERNEL_CS), "r" (KERNEL_DS), "r" (0));
+ : : "i" (KERNEL_CS), "r" (KERNEL_DS), "r" (0), "r" (PERCPU_DS));
#endif
+}
+
+void
+gdt_init(void)
+{
+ gdt_fill(0, gdt);
+
+ reload_segs();
+
#ifdef MACH_PV_PAGETABLES
#if VM_MIN_KERNEL_ADDRESS != LINEAR_MIN_KERNEL_ADDRESS
/* things now get shifted */
@@ -128,3 +155,12 @@ gdt_init(void)
#endif /* MACH_PV_PAGETABLES */
}
+#if NCPUS > 1
+void
+ap_gdt_init(int cpu)
+{
+ gdt_fill(cpu, mp_gdt[cpu]);
+
+ reload_segs();
+}
+#endif