summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2020-03-29 17:13:12 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2020-03-29 17:13:12 +0200
commit4d79b40a53d855c41137fa44bcafa62f5ae9f55d (patch)
tree71abc7f8dca9b62de1459925132d6679f13bce2a
parent7d26734f9144243f1fa5a0dfbc57a21be4a59472 (diff)
Fix 64bit TSS/LDT system descriptors
* i386/i386/seg.h (real_descriptor64): New structure. (fill_descriptor64): New function. * i386/i386/gdt.h [__x86_64__] (KERNEL_TSS): Set to 0x40 instead of 0x20. [__x86_64__] (USER_TSS): Set to 0x58 instead of 0x30. [__x86_64__] (GDTSZ): Set to 12 instead of 11. (_fill_gdt_descriptor): New macro. (_fill_gdt_descriptor64, fill_gdt_descriptor64): New macros. (_fill_gdt_sys_descriptor, fill_gdt_sys_descriptor): New macros. * i386/i386/ktss.c (ktss_init): Use fill_gdt_sys_descriptor instead of fill_gdt_descriptor to set KERNEL_TSS GDT entry. * i386/i386/ldt.c (ldt_init): Likewise for KERNEL_LDT GDT entry. * i386/i386/ldt.h (fill_ldt_descriptor, fill_ldt_gate): Use sel_idx instead of reimplementing it. * i386/i386/mp_desc.c (mp_desc_init): Use _fill_gdt_sys_descriptor instead of reimplementing it.
-rw-r--r--i386/i386/gdt.h59
-rw-r--r--i386/i386/ktss.c10
-rw-r--r--i386/i386/ldt.c12
-rw-r--r--i386/i386/ldt.h6
-rw-r--r--i386/i386/mp_desc.c7
-rw-r--r--i386/i386/seg.h50
6 files changed, 117 insertions, 27 deletions
diff --git a/i386/i386/gdt.h b/i386/i386/gdt.h
index d865640b..9879ad3e 100644
--- a/i386/i386/gdt.h
+++ b/i386/i386/gdt.h
@@ -40,28 +40,79 @@
*/
#define KERNEL_CS (0x08 | KERNEL_RING) /* kernel code */
#define KERNEL_DS (0x10 | KERNEL_RING) /* kernel data */
+
+
#ifndef MACH_PV_DESCRIPTORS
#define KERNEL_LDT 0x18 /* master LDT */
#endif /* MACH_PV_DESCRIPTORS */
+
+#ifdef __x86_64__
+/* LDT needs two entries */
+#define KERNEL_TSS 0x40 /* master TSS (uniprocessor) */
+#else
#define KERNEL_TSS 0x20 /* master TSS (uniprocessor) */
+#endif
+
+
#define USER_LDT 0x28 /* place for per-thread LDT */
+
+#ifdef __x86_64__
+/* LDT needs two entries */
+#define USER_TSS 0x58 /* place for per-thread TSS
+ that holds IO bitmap */
+#else
#define USER_TSS 0x30 /* place for per-thread TSS
that holds IO bitmap */
+#endif
+
+
#ifndef MACH_PV_DESCRIPTORS
#define LINEAR_DS 0x38 /* linear mapping */
#endif /* MACH_PV_DESCRIPTORS */
-/* 0x40 was USER_FPREGS, now free */
-#define USER_GDT 0x48 /* user-defined GDT entries */
+/* 0x40 was USER_FPREGS, now used by TSS in 64bit mode */
+
+#define USER_GDT 0x48 /* user-defined 32bit GDT entries */
#define USER_GDT_SLOTS 2
-#define GDTSZ (USER_GDT/8 + USER_GDT_SLOTS)
+/* 0x58 used by user TSS in 64bit mode */
+
+#ifdef __x86_64__
+#define GDTSZ sel_idx(0x60)
+#else
+#define GDTSZ sel_idx(0x58)
+#endif
extern struct real_descriptor gdt[GDTSZ];
/* Fill a segment descriptor in the GDT. */
+#define _fill_gdt_descriptor(_gdt, segment, base, limit, access, sizebits) \
+ fill_descriptor(&_gdt[sel_idx(segment)], base, limit, access, sizebits)
+
#define fill_gdt_descriptor(segment, base, limit, access, sizebits) \
- fill_descriptor(&gdt[segment/8], base, limit, access, sizebits)
+ _fill_gdt_descriptor(gdt, segment, base, limit, access, sizebits)
+
+/* 64bit variant */
+#ifdef __x86_64__
+#define _fill_gdt_descriptor64(_gdt, segment, base, limit, access, sizebits) \
+ fill_descriptor64((struct real_descriptor64 *) &_gdt[sel_idx(segment)], base, limit, access, sizebits)
+
+#define fill_gdt_descriptor64(segment, base, limit, access, sizebits) \
+ _fill_gdt_descriptor64(gdt, segment, base, limit, access, sizebits)
+#endif
+
+/* System descriptor variants */
+#ifdef __x86_64__
+#define _fill_gdt_sys_descriptor(_gdt, segment, base, limit, access, sizebits) \
+ _fill_gdt_descriptor64(_gdt, segment, base, limit, access, sizebits)
+#define fill_gdt_sys_descriptor(segment, base, limit, access, sizebits) \
+ fill_gdt_descriptor64(segment, base, limit, access, sizebits)
+#else
+#define _fill_gdt_sys_descriptor(_gdt, segment, base, limit, access, sizebits) \
+ _fill_gdt_descriptor(_gdt, segment, base, limit, access, sizebits)
+#define fill_gdt_sys_descriptor(segment, base, limit, access, sizebits) \
+ fill_gdt_descriptor(segment, base, limit, access, sizebits)
+#endif
extern void gdt_init(void);
diff --git a/i386/i386/ktss.c b/i386/i386/ktss.c
index 62de2a27..917e6305 100644
--- a/i386/i386/ktss.c
+++ b/i386/i386/ktss.c
@@ -51,14 +51,10 @@ ktss_init(void)
if (hyp_stack_switch(KERNEL_DS, (unsigned long)(exception_stack+1024)))
panic("couldn't register exception stack\n");
#else /* MACH_RING1 */
-
-#ifdef __x86_64__
-#warning FIXME
-#endif
/* Initialize the master TSS descriptor. */
- fill_gdt_descriptor(KERNEL_TSS,
- kvtolin(&ktss), sizeof(struct task_tss) - 1,
- ACC_PL_K|ACC_TSS, 0);
+ fill_gdt_sys_descriptor(KERNEL_TSS,
+ kvtolin(&ktss), sizeof(struct task_tss) - 1,
+ ACC_PL_K|ACC_TSS, 0);
/* Initialize the master TSS. */
ktss.tss.ss0 = KERNEL_DS;
diff --git a/i386/i386/ldt.c b/i386/i386/ldt.c
index 99d2f7fe..261df93a 100644
--- a/i386/i386/ldt.c
+++ b/i386/i386/ldt.c
@@ -47,22 +47,18 @@ struct real_descriptor ldt[LDTSZ];
void
ldt_init(void)
{
-#ifdef __x86_64__
-#warning FIXME
-#endif
-
#ifdef MACH_PV_DESCRIPTORS
#ifdef MACH_PV_PAGETABLES
pmap_set_page_readwrite(ldt);
#endif /* MACH_PV_PAGETABLES */
#else /* MACH_PV_DESCRIPTORS */
/* Initialize the master LDT descriptor in the GDT. */
- fill_gdt_descriptor(KERNEL_LDT,
- kvtolin(&ldt), sizeof(ldt)-1,
- ACC_PL_K|ACC_LDT, 0);
+ fill_gdt_sys_descriptor(KERNEL_LDT,
+ kvtolin(&ldt), sizeof(ldt)-1,
+ ACC_PL_K|ACC_LDT, 0);
#endif /* MACH_PV_DESCRIPTORS */
- /* Initialize the LDT descriptors. */
+ /* Initialize the 32bit LDT descriptors. */
fill_ldt_gate(USER_SCALL,
(vm_offset_t)&syscall, KERNEL_CS,
ACC_PL_U|ACC_CALL_GATE, 0);
diff --git a/i386/i386/ldt.h b/i386/i386/ldt.h
index 81c49782..1f0d7014 100644
--- a/i386/i386/ldt.h
+++ b/i386/i386/ldt.h
@@ -56,12 +56,12 @@
extern struct real_descriptor ldt[LDTSZ];
-/* Fill a segment descriptor in the LDT. */
+/* Fill a 32bit segment descriptor in the LDT. */
#define fill_ldt_descriptor(selector, base, limit, access, sizebits) \
- fill_descriptor(&ldt[selector/8], base, limit, access, sizebits)
+ fill_descriptor(&ldt[sel_idx(selector)], base, limit, access, sizebits)
#define fill_ldt_gate(selector, offset, dest_selector, access, word_count) \
- fill_gate((struct real_gate*)&ldt[selector/8], \
+ fill_gate((struct real_gate*)&ldt[sel_idx(selector)], \
offset, dest_selector, access, word_count)
void ldt_init(void);
diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c
index d62d4958..07cc389a 100644
--- a/i386/i386/mp_desc.c
+++ b/i386/i386/mp_desc.c
@@ -146,14 +146,11 @@ mp_desc_init(int mycpu)
#ifdef MACH_RING1
panic("TODO %s:%d\n",__FILE__,__LINE__);
#else /* MACH_RING1 */
-#ifdef __x86_64__
-#warning FIXME
-#endif
- fill_descriptor(&mpt->gdt[sel_idx(KERNEL_LDT)],
+ _fill_gdt_sys_descriptor(mpt->gdt, KERNEL_LDT,
(unsigned)&mpt->ldt,
LDTSZ * sizeof(struct real_descriptor) - 1,
ACC_P|ACC_PL_K|ACC_LDT, 0);
- fill_descriptor(&mpt->gdt[sel_idx(KERNEL_TSS)],
+ _fill_gdt_sys_descriptor(mpt->gdt, KERNEL_TSS,
(unsigned)&mpt->ktss,
sizeof(struct task_tss) - 1,
ACC_P|ACC_PL_K|ACC_TSS, 0);
diff --git a/i386/i386/seg.h b/i386/i386/seg.h
index 86e73c34..b1a14fe4 100644
--- a/i386/i386/seg.h
+++ b/i386/i386/seg.h
@@ -59,6 +59,22 @@ struct real_descriptor {
base_high:8; /* base 24..31 */
};
+#ifdef __x86_64__
+struct real_descriptor64 {
+ unsigned int limit_low:16, /* limit 0..15 */
+ base_low:16, /* base 0..15 */
+ base_med:8, /* base 16..23 */
+ access:8, /* access byte */
+ limit_high:4, /* limit 16..19 */
+ granularity:4, /* granularity */
+ base_high:8, /* base 24..31 */
+ base_ext:32, /* base 32..63 */
+ reserved1:8,
+ zero:5,
+ reserved2:19;
+};
+#endif
+
struct real_gate {
unsigned int offset_low:16, /* offset 0..15 */
selector:16,
@@ -189,6 +205,40 @@ fill_descriptor(struct real_descriptor *_desc, unsigned base, unsigned limit,
#endif /* MACH_PV_DESCRIPTORS */
}
+#ifdef __x86_64__
+MACH_INLINE void
+fill_descriptor64(struct real_descriptor64 *_desc, unsigned long base, unsigned limit,
+ unsigned char access, unsigned char sizebits)
+{
+ /* TODO: when !MACH_PV_DESCRIPTORS, setting desc and just memcpy isn't simpler actually */
+#ifdef MACH_PV_DESCRIPTORS
+ struct real_descriptor64 __desc, *desc = &__desc;
+#else /* MACH_PV_DESCRIPTORS */
+ struct real_descriptor64 *desc = _desc;
+#endif /* MACH_PV_DESCRIPTORS */
+ if (limit > 0xfffff)
+ {
+ limit >>= 12;
+ sizebits |= SZ_G;
+ }
+ desc->limit_low = limit & 0xffff;
+ desc->base_low = base & 0xffff;
+ desc->base_med = (base >> 16) & 0xff;
+ desc->access = access | ACC_P;
+ desc->limit_high = limit >> 16;
+ desc->granularity = sizebits;
+ desc->base_high = base >> 24;
+ desc->base_ext = base >> 32;
+ desc->reserved1 = 0;
+ desc->zero = 0;
+ desc->reserved2 = 0;
+#ifdef MACH_PV_DESCRIPTORS
+ if (hyp_do_update_descriptor(kv_to_ma(_desc), *(uint64_t*)desc))
+ panic("couldn't update descriptor(%lu to %08lx%08lx)\n", (vm_offset_t) kv_to_ma(_desc), *(((unsigned long*)desc)+1), *(unsigned long *)desc);
+#endif /* MACH_PV_DESCRIPTORS */
+}
+#endif
+
/* Fill a gate with particular values. */
MACH_INLINE void
fill_gate(struct real_gate *gate, unsigned offset, unsigned short selector,