aboutsummaryrefslogtreecommitdiff
path: root/sys/i386/i386/sys_machdep.c
diff options
context:
space:
mode:
authorKip Macy <kmacy@FreeBSD.org>2008-08-15 20:51:31 +0000
committerKip Macy <kmacy@FreeBSD.org>2008-08-15 20:51:31 +0000
commit93ee134a24fa25fde49b66da24f4262f37bf3249 (patch)
tree01c30bdd7553d9c3ff945b2422e697cffe0f9b20 /sys/i386/i386/sys_machdep.c
parent66f8d384cf1352e7269973271766595f12b2e2c1 (diff)
downloadsrc-93ee134a24fa25fde49b66da24f4262f37bf3249.tar.gz
src-93ee134a24fa25fde49b66da24f4262f37bf3249.zip
Integrate support for xen in to i386 common code.
MFC after: 1 month
Notes
Notes: svn path=/head/; revision=181775
Diffstat (limited to 'sys/i386/i386/sys_machdep.c')
-rw-r--r--sys/i386/i386/sys_machdep.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c
index 97ebe3477be4..f792f2a5d2a6 100644
--- a/sys/i386/i386/sys_machdep.c
+++ b/sys/i386/i386/sys_machdep.c
@@ -58,6 +58,20 @@ __FBSDID("$FreeBSD$");
#include <security/audit/audit.h>
+#ifdef XEN
+#include <machine/xen/xenfunc.h>
+
+void i386_reset_ldt(struct proc_ldt *pldt);
+
+void
+i386_reset_ldt(struct proc_ldt *pldt)
+{
+ xen_set_ldt((vm_offset_t)pldt->ldt_base, pldt->ldt_len);
+}
+#else
+#define i386_reset_ldt(x)
+#endif
+
#include <vm/vm_kern.h> /* for kernel_map */
#define MAX_LD 8192
@@ -164,7 +178,12 @@ sysarch(td, uap)
*/
sd.sd_lobase = base & 0xffffff;
sd.sd_hibase = (base >> 24) & 0xff;
+#ifdef XEN
+ /* need to do nosegneg like Linux */
+ sd.sd_lolimit = (HYPERVISOR_VIRT_START >> 12) & 0xffff;
+#else
sd.sd_lolimit = 0xffff; /* 4GB limit, wraps around */
+#endif
sd.sd_hilimit = 0xf;
sd.sd_type = SDT_MEMRWA;
sd.sd_dpl = SEL_UPL;
@@ -174,7 +193,12 @@ sysarch(td, uap)
sd.sd_gran = 1;
critical_enter();
td->td_pcb->pcb_fsd = sd;
+#ifdef XEN
+ HYPERVISOR_update_descriptor(vtomach(&PCPU_GET(fsgs_gdt)[0]),
+ *(uint64_t *)&sd);
+#else
PCPU_GET(fsgs_gdt)[0] = sd;
+#endif
critical_exit();
td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
}
@@ -194,7 +218,13 @@ sysarch(td, uap)
*/
sd.sd_lobase = base & 0xffffff;
sd.sd_hibase = (base >> 24) & 0xff;
+
+#ifdef XEN
+ /* need to do nosegneg like Linux */
+ sd.sd_lolimit = (HYPERVISOR_VIRT_START >> 12) & 0xffff;
+#else
sd.sd_lolimit = 0xffff; /* 4GB limit, wraps around */
+#endif
sd.sd_hilimit = 0xf;
sd.sd_type = SDT_MEMRWA;
sd.sd_dpl = SEL_UPL;
@@ -204,7 +234,12 @@ sysarch(td, uap)
sd.sd_gran = 1;
critical_enter();
td->td_pcb->pcb_gsd = sd;
+#ifdef XEN
+ HYPERVISOR_update_descriptor(vtomach(&PCPU_GET(fsgs_gdt)[1]),
+ *(uint64_t *)&sd);
+#else
PCPU_GET(fsgs_gdt)[1] = sd;
+#endif
critical_exit();
load_gs(GSEL(GUGS_SEL, SEL_UPL));
}
@@ -360,6 +395,10 @@ set_user_ldt(struct mdproc *mdp)
}
pldt = mdp->md_ldt;
+#ifdef XEN
+ i386_reset_ldt(pldt);
+ PCPU_SET(currentldt, (int)pldt);
+#else
#ifdef SMP
gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd;
#else
@@ -367,6 +406,7 @@ set_user_ldt(struct mdproc *mdp)
#endif
lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
+#endif /* XEN */
if (dtlocked)
mtx_unlock_spin(&dt_lock);
}
@@ -385,6 +425,44 @@ set_user_ldt_rv(struct vmspace *vmsp)
}
#endif
+#ifdef XEN
+
+/*
+ * dt_lock must be held. Returns with dt_lock held.
+ */
+struct proc_ldt *
+user_ldt_alloc(struct mdproc *mdp, int len)
+{
+ struct proc_ldt *pldt, *new_ldt;
+
+ mtx_assert(&dt_lock, MA_OWNED);
+ mtx_unlock_spin(&dt_lock);
+ MALLOC(new_ldt, struct proc_ldt *, sizeof(struct proc_ldt),
+ M_SUBPROC, M_WAITOK);
+
+ new_ldt->ldt_len = len = NEW_MAX_LD(len);
+ new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map,
+ round_page(len * sizeof(union descriptor)));
+ if (new_ldt->ldt_base == NULL) {
+ FREE(new_ldt, M_SUBPROC);
+ return NULL;
+ }
+ new_ldt->ldt_refcnt = 1;
+ new_ldt->ldt_active = 0;
+
+ if ((pldt = mdp->md_ldt)) {
+ if (len > pldt->ldt_len)
+ len = pldt->ldt_len;
+ bcopy(pldt->ldt_base, new_ldt->ldt_base,
+ len * sizeof(union descriptor));
+ } else {
+ bcopy(ldt, new_ldt->ldt_base, PAGE_SIZE);
+ }
+ pmap_map_readonly(kernel_pmap, (vm_offset_t)new_ldt->ldt_base,
+ new_ldt->ldt_len*sizeof(union descriptor));
+ return new_ldt;
+}
+#else
/*
* dt_lock must be held. Returns with dt_lock held.
*/
@@ -423,6 +501,7 @@ user_ldt_alloc(struct mdproc *mdp, int len)
return (new_ldt);
}
+#endif /* !XEN */
/*
* Must be called with dt_lock held. Returns with dt_lock unheld.
@@ -667,7 +746,23 @@ again:
td->td_retval[0] = uap->start;
return (error);
}
+#ifdef XEN
+static int
+i386_set_ldt_data(struct thread *td, int start, int num,
+ union descriptor *descs)
+{
+ struct mdproc *mdp = &td->td_proc->p_md;
+ struct proc_ldt *pldt = mdp->md_ldt;
+ mtx_assert(&dt_lock, MA_OWNED);
+
+ /* Fill in range */
+ bcopy(descs,
+ &((union descriptor *)(pldt->ldt_base))[start],
+ num * sizeof(union descriptor));
+ return (0);
+}
+#else
static int
i386_set_ldt_data(struct thread *td, int start, int num,
union descriptor *descs)
@@ -683,6 +778,7 @@ i386_set_ldt_data(struct thread *td, int start, int num,
num * sizeof(union descriptor));
return (0);
}
+#endif /* !XEN */
static int
i386_ldt_grow(struct thread *td, int len)