mirror of
https://git.freebsd.org/ports.git
synced 2025-06-11 15:50:33 -04:00
(This fixes the problems that one user saw which I couldn't reproduce.) - Bump PORTREVISION
112 lines
3 KiB
Text
112 lines
3 KiB
Text
Index: kqemu-freebsd.c
|
|
@@ -38,6 +38,14 @@
|
|
#else
|
|
#include <machine/npx.h>
|
|
#endif
|
|
+#ifdef __x86_64__
|
|
+#include <sys/smp.h>
|
|
+#include <sys/pcpu.h>
|
|
+#include <machine/pcb.h>
|
|
+#include <machine/specialreg.h>
|
|
+#include <machine/segments.h>
|
|
+#include <machine/tss.h>
|
|
+#endif
|
|
|
|
#include "kqemu-kernel.h"
|
|
|
|
@@ -248,6 +256,57 @@
|
|
va_end(ap);
|
|
}
|
|
|
|
+#ifdef __x86_64__
|
|
+int kqemu_cpu0gdtfixed;
|
|
+int kqemu_gdts_used;
|
|
+struct user_segment_descriptor *kqemu_gdts;
|
|
+struct region_descriptor kqemu_r_newgdt;
|
|
+extern struct pcpu __pcpu[];
|
|
+
|
|
+/* called with interrupts disabled */
|
|
+void CDECL kqemu_tss_fixup(unsigned long kerngdtbase)
|
|
+{
|
|
+ int gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
|
|
+ unsigned cpuid = PCPU_GET(cpuid);
|
|
+ struct user_segment_descriptor *newgdt = gdt;
|
|
+
|
|
+ if (mp_ncpus <= 1 || kerngdtbase != (unsigned long)gdt)
|
|
+ /* UP host or gdt already moved, nothing to do */
|
|
+ return;
|
|
+ if (cpuid) {
|
|
+ /* move gdts of all but first cpu */
|
|
+ if (!kqemu_gdts)
|
|
+ /*
|
|
+ * XXX gdt is allocated as
|
|
+ * struct user_segment_descriptor gdt[NGDT * MAXCPU];
|
|
+ * so it has room for the moved copies; need to allocate at
|
|
+ * kldload (and only free if kqemu_gdts_used is zero) should this
|
|
+ * change in the future
|
|
+ */
|
|
+ kqemu_gdts = &gdt[NGDT];
|
|
+ ++kqemu_gdts_used;
|
|
+ newgdt = &kqemu_gdts[NGDT * (cpuid - 1)];
|
|
+ bcopy(gdt, newgdt, NGDT * sizeof(gdt[0]));
|
|
+ kqemu_r_newgdt.rd_limit = NGDT * sizeof(gdt[0]) - 1;
|
|
+ kqemu_r_newgdt.rd_base = (long) newgdt;
|
|
+ } else {
|
|
+ if (kqemu_cpu0gdtfixed)
|
|
+ return;
|
|
+ ++kqemu_cpu0gdtfixed;
|
|
+ }
|
|
+ gdt_segs[GPROC0_SEL].ssd_base = (long) &common_tss[cpuid];
|
|
+ ssdtosyssd(&gdt_segs[GPROC0_SEL],
|
|
+ (struct system_segment_descriptor *)&newgdt[GPROC0_SEL]);
|
|
+ if (cpuid) {
|
|
+ lgdt(&kqemu_r_newgdt);
|
|
+ wrmsr(MSR_GSBASE, (u_int64_t)&__pcpu[cpuid]);
|
|
+ wrmsr(MSR_KGSBASE, curthread->td_pcb->pcb_gsbase);
|
|
+ wrmsr(MSR_FSBASE, curthread->td_pcb->pcb_fsbase);
|
|
+ }
|
|
+ ltr(gsel_tss);
|
|
+}
|
|
+#endif
|
|
+
|
|
struct kqemu_instance {
|
|
#if __FreeBSD_version >= 500000
|
|
TAILQ_ENTRY(kqemu_instance) kqemu_ent;
|
|
Index: common/kernel.c
|
|
@@ -1025,6 +1025,9 @@
|
|
#ifdef __x86_64__
|
|
uint16_t saved_ds, saved_es;
|
|
unsigned long fs_base, gs_base;
|
|
+#ifdef __FreeBSD__
|
|
+ struct kqemu_global_state *g = s->global_state;
|
|
+#endif
|
|
#endif
|
|
|
|
#ifdef PROFILE
|
|
@@ -1096,6 +1099,14 @@
|
|
apic_nmi_mask = apic_save_and_disable_nmi(s);
|
|
}
|
|
|
|
+#ifdef __FreeBSD__
|
|
+#ifdef __x86_64__
|
|
+ spin_lock(&g->lock);
|
|
+ asm volatile ("sgdt %0" : : "m" (s->kernel_gdt));
|
|
+ kqemu_tss_fixup(s->kernel_gdt.base);
|
|
+ spin_unlock(&g->lock);
|
|
+#endif
|
|
+#endif
|
|
/* load breakpoint registers and avoid setting them if in the
|
|
monitor address space. We suppose that no breakpoints are
|
|
set by the host OS for this process */
|
|
Index: kqemu-kernel.h
|
|
@@ -48,4 +48,10 @@
|
|
|
|
void CDECL kqemu_log(const char *fmt, ...);
|
|
|
|
+#ifdef __FreeBSD__
|
|
+#ifdef __x86_64__
|
|
+void CDECL kqemu_tss_fixup(unsigned long kerngdtbase);
|
|
+#endif
|
|
+#endif
|
|
+
|
|
#endif /* KQEMU_KERNEL_H */
|