b31f8823d179c1a5e9867d9b87b48a1f32ddc5a6
[barrelfish] / lib / barrelfish / arch / x86_64 / ldt.c
1 /**
2  * \file
3  * \brief Local descriptor table (LDT) management
4  */
5
6 /*
7  * Copyright (c) 2011, 2013, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <barrelfish/barrelfish.h>
16 #include <barrelfish/dispatch.h>
17 #include <barrelfish/dispatcher_arch.h>
18 #include <barrelfish/curdispatcher_arch.h>
19 #include <barrelfish/syscalls.h>
20 #include <barrelfish/ldt.h>
21 #include <arch/ldt.h>
22 #ifdef __k1om__
23 #include <target/k1om/barrelfish_kpi/cpu_target.h> // segment_descriptor
24 #else
25 #include <target/x86_64/barrelfish_kpi/cpu_target.h> // segment_descriptor
26 #endif
27 #include <barrelfish_kpi/cpu_arch.h> // segment_descriptor
28 #include <stdio.h>
29 #include <string.h>
30
31 #define LDT_NENTRIES    512     ///< Number of entries in the statically-sized LDT
32
33 /// Local segment descriptor table. Shared by all dispatchers in an address space.
34 // (XXX: coherence assumption)
35 static union segment_descriptor ldt[LDT_NENTRIES];
36
37 /// Spinlock protecting LDT in spanned domains
38 // (XXX: coherence assumption)
39 static spinlock_t ldt_spinlock;
40
41 #ifdef ARRAKIS
42
43 /*
44  * AMD64 Segmentation Data Structures and definitions
45  */
46
47 /*
48  * Selectors
49  */
50
51 #define SEL_RPL_MASK    3       /* requester priv level */
52 #define ISPL(s) ((s)&3)         /* what is the priority level of a selector */
53 #define SEL_KPL 0               /* kernel priority level */
54 #define SEL_UPL 3               /* user priority level */
55 #define ISLDT(s)        ((s)&SEL_LDT)   /* is it local or global */
56 #define SEL_LDT 4               /* local descriptor table */
57 #define IDXSEL(s)       (((s)>>3) & 0x1fff)             /* index of selector */
58 #define LSEL(s,r)       (((s)<<3) | SEL_LDT | r)        /* a local selector */
59 #define GSEL(s,r)       (((s)<<3) | r)                  /* a global selector */
60
61 /**
62  * Gate descriptors (e.g. indirect descriptors, trap, interrupt etc. 128 bit)
63  * Only interrupt and trap gates have gd_ist.
64  */
65 struct  gate_descriptor {
66     uint64_t gd_looffset:16;       /* gate offset (lsb) */
67     uint64_t gd_selector:16;       /* gate segment selector */
68     uint64_t gd_ist:3;             /* IST table index */
69     uint64_t gd_xx:5;              /* unused */
70     uint64_t gd_type:5;            /* segment type */
71     uint64_t gd_dpl:2;             /* segment descriptor priority level */
72     uint64_t gd_p:1;               /* segment descriptor present */
73     uint64_t gd_hioffset:48;       /* gate offset (msb) */
74     uint64_t sd_xx1:32;
75 } __attribute__((packed));
76
77 /* system segments and gate types */
78 #define SDT_SYSNULL      0      /* system null */
79 #define SDT_SYSLDT       2      /* system 64 bit local descriptor table */
80 #define SDT_SYSTSS       9      /* system available 64 bit TSS */
81 #define SDT_SYSBSY      11      /* system busy 64 bit TSS */
82 #define SDT_SYSCGT      12      /* system 64 bit call gate */
83 #define SDT_SYSIGT      14      /* system 64 bit interrupt gate */
84 #define SDT_SYSTGT      15      /* system 64 bit trap gate */
85
86 /* memory segment types */
87 #define SDT_MEMRO       16      /* memory read only */
88 #define SDT_MEMROA      17      /* memory read only accessed */
89 #define SDT_MEMRW       18      /* memory read write */
90 #define SDT_MEMRWA      19      /* memory read write accessed */
91 #define SDT_MEMROD      20      /* memory read only expand dwn limit */
92 #define SDT_MEMRODA     21      /* memory read only expand dwn limit accessed */
93 #define SDT_MEMRWD      22      /* memory read write expand dwn limit */
94 #define SDT_MEMRWDA     23      /* memory read write expand dwn limit accessed */
95 #define SDT_MEME        24      /* memory execute only */
96 #define SDT_MEMEA       25      /* memory execute only accessed */
97 #define SDT_MEMER       26      /* memory execute read */
98 #define SDT_MEMERA      27      /* memory execute read accessed */
99 #define SDT_MEMEC       28      /* memory execute only conforming */
100 #define SDT_MEMEAC      29      /* memory execute only accessed conforming */
101 #define SDT_MEMERC      30      /* memory execute read conforming */
102 #define SDT_MEMERAC     31      /* memory execute read accessed conforming */
103
104 /*
105  * Size of IDT table
106  */
107 #define NIDT    256             /* 32 reserved, 16 h/w, 0 s/w, linux's 0x80 */
108
109 /*
110  * Entries in the Global Descriptor Table (GDT)
111  */
112 #define NULL_SEL        0       /**< Null descriptor */
113 #define KCODE_SEL       1       /**< Kernel code descriptor */
114 #define KSTACK_SEL      2       /**< Shared user/kernel stack descriptor */
115 #define USTACK_SEL      3       /**< User stack descriptor */
116 #define UCODE_SEL       4       /**< User code descriptor */
117 #define TSS_LO_SEL      5       /**< Task State Segment (TSS) -- low 64bit */
118 #define TSS_HI_SEL      6       /**< Task State Segment (TSS) -- high 64bit */
119 #define LDT_LO_SEL      7       /**< Local descriptor table (LDT) -- low */
120 #define LDT_HI_SEL      8       /**< Local descriptor table (LDT) -- high */
121 #define NGDT_MEM        9       /**< Number of descriptors */
122
123 /**
124  * region descriptors, used to load gdt/idt tables before segments yet exist.
125  */
126 struct region_descriptor {
127     uint16_t rd_limit;          /**< segment extent */
128     uint64_t rd_base;           /**< base address  */
129 } __attribute__((packed));
130
131 struct task_state_segment {
132     uint32_t    reserved;
133     uint64_t    rsp[3];
134     uint64_t    reserved2;
135     uint64_t    ist[7];
136     uint64_t    reserved3;
137     uint16_t    reserved4;
138     uint16_t    iomap_base;
139 } __attribute__ ((packed));
140
141 /**
142  * \brief Global Task State Segment (TSS).
143  *
144  * This is the global, static and only Task State Segment (TSS). It is used
145  * for interrupt and exception handling (stack setup) while in user-space.
146  */
147 static struct task_state_segment tss __attribute__ ((aligned (4)));
148
149 union segment_descriptor gdt[] __attribute__ ((aligned (4))) = {
150     [NULL_SEL] = {   // Null segment
151         .raw = 0
152     },
153     [KCODE_SEL] = {   // Kernel code segment
154         .d = {
155             .lo_limit = 0xffff,
156             .lo_base = 0,
157             .type = 0xa,
158             .system_desc = 1,
159             .privilege_level = SEL_KPL,
160             .present = 1,
161             .hi_limit = 0xf,
162             .available = 0,
163             .long_mode = 1,
164             .operation_size = 0,
165             .granularity = 1,
166             .hi_base = 0
167         }
168     },
169     [KSTACK_SEL] = {   // Kernel stack segment
170         .d = {
171             .lo_limit = 0xffff,
172             .lo_base = 0,
173             .type = 2,
174             .system_desc = 1,
175             .privilege_level = SEL_KPL,
176             .present = 1,
177             .hi_limit = 0xf,
178             .available = 0,
179             .long_mode = 1,
180             .operation_size = 0,
181             .granularity = 1,
182             .hi_base = 0
183         }
184     },
185     [USTACK_SEL] = {   // User stack segment
186         .d = {
187             .lo_limit = 0xffff,
188             .lo_base = 0,
189             .type = 2,
190             .system_desc = 1,
191             .privilege_level = SEL_UPL,
192             .present = 1,
193             .hi_limit = 0xf,
194             .available = 0,
195             .long_mode = 1,
196             .operation_size = 0,
197             .granularity = 1,
198             .hi_base = 0
199         }
200     },
201     [UCODE_SEL] = {   // User code segment
202         .d = {
203             .lo_limit = 0xffff,
204             .lo_base = 0,
205             .type = 0xa,
206             .system_desc = 1,
207             .privilege_level = SEL_UPL,
208             .present = 1,
209             .hi_limit = 0xf,
210             .available = 0,
211             .long_mode = 1,
212             .operation_size = 0,
213             .granularity = 1,
214             .hi_base = 0
215         }
216     },
217     [TSS_LO_SEL] = {   // Global Task State Segment (TSS), lower 8 bytes
218         .sys_lo = {
219             .lo_limit = sizeof(tss) & 0xffff,
220             .type = SDT_SYSTSS,
221             .privilege_level = SEL_KPL,
222             .present = 1,
223             .hi_limit = (sizeof(tss) >> 16) & 0xf,
224             .available = 0,
225             .granularity = 0,
226         }
227     },
228     [TSS_HI_SEL] = {   // Global Task State Segment (TSS), upper 8 bytes
229         .sys_hi = {
230             .base = 0
231         }
232     },
233     [LDT_LO_SEL] = {    // Local descriptor table (LDT), lower 8 bytes
234         .sys_lo = {
235             .lo_limit = 0, // # 4k pages (since granularity = 1)
236             .lo_base = 0, // changed by context switch path when doing lldt
237             .type = 2, // LDT
238             .privilege_level = SEL_UPL,
239             .present = 1,
240             .hi_limit = 0,
241             .available = 0,
242             .granularity = 1,
243             .hi_base = 0
244         }
245     },
246     [LDT_HI_SEL] = {    // Local descriptor table (LDT), upper 8 bytes
247         .sys_hi = {
248             .base = 0 // changed by context switch path when doing lldt
249         }
250     },
251 };
252
253 static union segment_descriptor *ldt_descriptor = &gdt[LDT_LO_SEL];
254
255 /// Remember current LDT pointer, so we can avoid reloading it
256 static lvaddr_t current_ldt_base = -1;
257 static size_t current_ldt_npages;
258
259 static void maybe_reload_ldt(struct dispatcher_shared_x86_64 *disp, bool force_reload)
260 {
261     /* Read fields from user dispatcher once for consistency */
262     lvaddr_t ldt_base = disp->ldt_base;
263     size_t ldt_npages = disp->ldt_npages;
264
265     /* optimize out if this is the same as the previous LDT */
266     if (!force_reload && ldt_base == current_ldt_base
267         && ldt_npages == current_ldt_npages) {
268         return;
269     }
270
271     uint16_t selector = 0;
272
273     if (ldt_base != 0 && ldt_npages != 0) {
274         ldt_descriptor[0].sys_lo.lo_base = ldt_base & ((1ul << 24) - 1);
275         ldt_descriptor[0].sys_lo.hi_base = (ldt_base >> 24) & 0xff;
276         ldt_descriptor[1].sys_hi.base = ldt_base >> 32;
277         assert(ldt_descriptor[0].sys_lo.granularity != 0);
278         ldt_descriptor[0].sys_lo.lo_limit = ldt_npages;
279
280         selector = GSEL(LDT_LO_SEL, SEL_UPL);
281     }
282
283     __asm volatile("lldt %%ax"
284                    : /* No output */
285                    : "a" (selector));
286
287     current_ldt_base = ldt_base;
288     current_ldt_npages = ldt_npages;
289 }
290
291 /**
292  * \brief Setup default GDT.
293  *
294  * Loads the GDT register with the default GDT and reloads CS and SS
295  * to point to the new entries. Resets all other segment registers to null.
296  * Finally, completes setup of GDT to include TSS base address mapping and
297  * loads TSS into task register.
298  */
299 static void gdt_reset(struct dispatcher_generic *disp)
300 {
301     lvaddr_t                     ptss = (lvaddr_t)&tss;
302     struct region_descriptor    region = {
303         .rd_limit = sizeof(gdt),
304         .rd_base = (uint64_t)&gdt
305     };
306
307     // Load default GDT
308     __asm volatile("lgdt %[region]" :: [region] "m" (region));
309
310     // Reload segments
311     __asm volatile("mov %[null], %%ds      \n\t"
312                    "mov %[null], %%es      \n\t"
313                    "mov %[ss], %%ss        \n\t"
314                    "mov %[null], %%gs      \n\t"
315                    "mov %[null], %%fs      \n\t"
316                    "pushq %[cs]            \n\t"          // new CS
317                    "lea 1f(%%rip), %%rax   \n\t"          // jumps to after lret
318                    "pushq %%rax            \n\t"          // new IP
319                    "lretq                  \n\t"          // fake return
320                    "1:                     \n\t"          // we'll continue here
321                    : /* No Output */
322                    :
323                    [null] "r" (0),
324                    [ss] "r" (GSEL(KSTACK_SEL, SEL_KPL)),
325                    [cs] "i" (GSEL(KCODE_SEL, SEL_KPL))
326                    : "rax"
327                    );
328
329     // Complete setup of TSS descriptor (by inserting base address of TSS)
330     gdt[TSS_LO_SEL].sys_lo.lo_base = ptss & 0xffffff;
331     gdt[TSS_LO_SEL].sys_lo.hi_base = (ptss >> 24) & 0xff;
332     gdt[TSS_HI_SEL].sys_hi.base = ptss >> 32;
333
334     // Complete setup of TSS
335     tss.rsp[0] = (lvaddr_t)&disp->stack[DISPATCHER_STACK_WORDS];
336
337     // Load task state register
338     __asm volatile("ltr %%ax" :: "a" (GSEL(TSS_LO_SEL, SEL_KPL)));
339 }
340
341 /* Utility function for code below; initialises a gate_descriptor */
342 static void setgd(struct gate_descriptor *gd, void (* handler)(void),
343                   int ist, int type, int dpl, int selector)
344 {
345     memset(gd, 0, sizeof(struct gate_descriptor));
346     gd->gd_looffset = (uintptr_t)handler & ((1UL << 16) - 1);
347     gd->gd_hioffset = (uintptr_t)handler >> 16;
348     gd->gd_selector = selector;
349     gd->gd_ist = ist;
350     gd->gd_type = type;
351     gd->gd_dpl = dpl;
352     gd->gd_p = 1;
353 }
354
355 /**
356  * \brief Define IRQ handler number 'num'.
357  *
358  * This defines an interrupt handler for vector #num. The way this is done is
359  * quite tricky: A block of assembly is emitted, with a label pointing to
360  * the beginning of that block. The label is made known as a symbol by
361  * having a C function _declaration_ directly in front of the block. The
362  * symbol has to be defined extern, so it is global, but its ELF visibility
363  * is set "hidden", so that the symbol does not end up in the GOT. This is
364  * very important for keeping the code position-independent.
365  *
366  * The NOERR/ERR variants depend on whether the hardware delivers an error code.
367  */
368 #define HW_EXCEPTION_NOERR(num)                                         \
369     void __attribute__ ((visibility ("hidden"))) hwexc_##num(void);     \
370     __asm (                                                             \
371            "\t.text                                        \n\t"        \
372            "\t.type hwexc_"#num",@function                 \n\t"        \
373            "hwexc_"#num":                                  \n\t"        \
374            "pushq $0                /* dummy error code */ \n\t"        \
375            "pushq $"#num"           /* vector number */    \n\t"        \
376            "jmp    hwexc_common     /* common stuff */     \n\t"        \
377                                                                         )
378
379 #define HW_EXCEPTION_ERR(num)                                           \
380     void __attribute__ ((visibility ("hidden"))) hwexc_##num(void);     \
381     __asm (                                                             \
382            "\t.text                                        \n\t"        \
383            "\t.type hwexc_"#num",@function                 \n\t"        \
384            "hwexc_"#num":                                  \n\t"        \
385            "pushq $"#num"           /* vector number */    \n\t"        \
386            "jmp    hwexc_common     /* common stuff */     \n\t"        \
387                                                                         )
388
389 __asm (
390     ".text                                              \n\t"
391     "   .type hwexc_common ,@function                   \n\t"
392     /* a kernel fault means something bad happened, so we stack
393      * everything for the debugger to use, in the GDB frame format */
394     "hwexc_common:                                      \n\t"
395     "pushq 6*8(%rsp) /* SS */                           \n\t"
396     "pushq 4*8(%rsp) /* CS */                           \n\t"
397     "pushq 7*8(%rsp) /* EFLAGS */                       \n\t"
398     "pushq 5*8(%rsp) /* RIP */                          \n\t"
399     /* TODO: extend frame size and save FS/GS so we can resume afterwards */
400     "pushq %r15                                         \n\t"
401     "pushq %r14                                         \n\t"
402     "pushq %r13                                         \n\t"
403     "pushq %r12                                         \n\t"
404     "pushq %r11                                         \n\t"
405     "pushq %r10                                         \n\t"
406     "pushq %r9                                          \n\t"
407     "pushq %r8                                          \n\t"
408     "pushq 17*8(%rsp) /* RSP */                         \n\t"
409     "pushq %rbp                                         \n\t"
410     "pushq %rdi                                         \n\t"
411     "pushq %rsi                                         \n\t"
412     "pushq %rdx                                         \n\t"
413     "pushq %rcx                                         \n\t"
414     "pushq %rbx                                         \n\t"
415     "pushq %rax                                         \n\t"
416     "movq 20*8(%rsp), %rdi  /* vector number */         \n\t"
417     "movq 21*8(%rsp), %rsi  /* error code   */          \n\t"
418     "movq %rsp, %rdx       /* save area ptr*/           \n\t"
419     "jmp generic_handle_exception                       \n\t"
420 );
421
422 // CPU exceptions
423 HW_EXCEPTION_NOERR(0);
424 HW_EXCEPTION_NOERR(1);
425 HW_EXCEPTION_NOERR(2);
426 HW_EXCEPTION_NOERR(3);
427 HW_EXCEPTION_NOERR(4);
428 HW_EXCEPTION_NOERR(5);
429 HW_EXCEPTION_NOERR(6);
430 HW_EXCEPTION_NOERR(7);
431 HW_EXCEPTION_ERR(8);
432 HW_EXCEPTION_NOERR(9);
433 HW_EXCEPTION_ERR(10);
434 HW_EXCEPTION_ERR(11);
435 HW_EXCEPTION_ERR(12);
436 HW_EXCEPTION_ERR(13);
437 HW_EXCEPTION_ERR(14);
438 HW_EXCEPTION_NOERR(16);
439 HW_EXCEPTION_ERR(17);
440 HW_EXCEPTION_NOERR(18);
441 HW_EXCEPTION_NOERR(19);
442
443 // Reserved as "unhandled exception" handler
444 HW_EXCEPTION_NOERR(666);
445
446 /**
447  * \brief X86_64 register set
448  *
449  * As defined by GDB.
450  */
451 enum gdb_x86_64_register_nums {
452     GDB_X86_64_RAX_REG, GDB_X86_64_RBX_REG, GDB_X86_64_RCX_REG, GDB_X86_64_RDX_REG,
453     GDB_X86_64_RSI_REG, GDB_X86_64_RDI_REG, GDB_X86_64_RBP_REG, GDB_X86_64_RSP_REG,
454     GDB_X86_64_R8_REG, GDB_X86_64_R9_REG, GDB_X86_64_R10_REG, GDB_X86_64_R11_REG,
455     GDB_X86_64_R12_REG, GDB_X86_64_R13_REG, GDB_X86_64_R14_REG, GDB_X86_64_R15_REG,
456     GDB_X86_64_RIP_REG, GDB_X86_64_EFLAGS_REG, GDB_X86_64_CS_REG, GDB_X86_64_SS_REG,
457
458 /* these are not saved/used in 64-bit mode, and currently avoided
459     DS_REG, ES_REG, FS_REG, GS_REG,
460 */
461
462 /* these are not used yet:
463     ST0_REG, ST1_REG, ST2_REG, ST3_REG, ST4_REG, ST5_REG, ST6_REG, ST7_REG,
464
465     FCTRL_REG, FSTAT_REG, FTAG_REG, FISEG_REG,
466     FIOFF_REG, FOSEG_REG, FOOFF_REG, FOP_REG,
467
468     XMM0_REG, XMM1_REG, XMM2_REG, XMM3_REG, XMM4_REG, XMM5_REG,
469     XMM6_REG, XMM7_REG, XMM8_REG, XMM9_REG, XMM10_REG, XMM11_REG,
470     XMM12_REG, XMM13_REG, XMM14_REG, XMM15_REG,
471     MXCSR_REG
472 */
473
474     GDB_X86_64_NUM_REGS /* not a real register; must be last! */
475 };
476
477 void disp_pagefault(dispatcher_handle_t handle, lvaddr_t fault_address,
478                     uintptr_t error, lvaddr_t ip);
479
480 /**
481  * \brief Handles kernel exceptions
482  *
483  * \param vec   Vector number of exception
484  * \param error Error code from CPU, or 0 for an exception without an error code
485  * \param gdb_save_frame Pointer to save area for registers stacked by trap handler
486  */
487 static __attribute__ ((used))
488 void generic_handle_exception(uint64_t vec, uint64_t error,
489                               uintptr_t *gdb_save_frame)
490 {
491     // XXX: This assumes we're enabled. That's not always the case...
492
493     switch(vec) {
494     case IDT_PF:
495         {
496             // For now, disable the dispatcher and call classic exception handler code
497             dispatcher_handle_t handle = disp_disable();
498             lvaddr_t fault_address;
499             arch_registers_state_t *regs = dispatcher_get_enabled_save_area(handle);
500             __asm volatile("mov %%cr2, %[fault_address]"
501                            : [fault_address] "=r" (fault_address));
502
503             // Write registers to dispatcher save area
504             regs->rsp = gdb_save_frame[GDB_X86_64_RSP_REG];
505             regs->eflags = gdb_save_frame[GDB_X86_64_EFLAGS_REG];
506             regs->rip = gdb_save_frame[GDB_X86_64_RIP_REG];
507
508             disp_pagefault(handle, fault_address, error, regs->rip);
509         }
510         break;
511
512     default:
513         debug_printf("Unhandled exception %d at 0x%" PRIxPTR " (error code 0x%lx)\n",
514                      (int)vec, gdb_save_frame[GDB_X86_64_RIP_REG], error);
515         abort();
516         break;
517     }
518 }
519
520 /**
521  * \brief Interrupt Descriptor Table (IDT) for processor this kernel is running
522  * on.
523  */
524 static struct gate_descriptor idt[NIDT] __attribute__ ((aligned (16)));
525
526 /**
527  * \brief Sets up the default IDT for current CPU.
528  */
529 static void setup_default_idt(void)
530 {
531     struct region_descriptor region = {         // set default IDT
532         .rd_limit = NIDT * sizeof(idt[0]) - 1,
533         .rd_base = (uint64_t)&idt
534     };
535     int i;
536
537     // reset IDT
538     memset((void *)&idt, 0, NIDT * sizeof(idt[0]));
539
540     // initialize IDT with default generic handlers
541     for (i = 0; i < NIDT; i++)
542         setgd(&idt[i], hwexc_666, 0, SDT_SYSIGT, SEL_KPL,
543               GSEL(KCODE_SEL, SEL_KPL));
544
545     /* Setup exception handlers */
546     setgd(&idt[0], hwexc_0, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
547     setgd(&idt[1], hwexc_1, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
548     setgd(&idt[2], hwexc_2, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
549     setgd(&idt[3], hwexc_3, 0, SDT_SYSTGT, SEL_UPL, GSEL(KCODE_SEL, SEL_KPL));
550     setgd(&idt[4], hwexc_4, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
551     setgd(&idt[5], hwexc_5, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
552     setgd(&idt[6], hwexc_6, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
553     setgd(&idt[7], hwexc_7, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
554     setgd(&idt[8], hwexc_8, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
555     setgd(&idt[9], hwexc_9, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
556     setgd(&idt[10], hwexc_10, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
557     setgd(&idt[11], hwexc_11, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
558     setgd(&idt[12], hwexc_12, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
559     setgd(&idt[13], hwexc_13, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
560     setgd(&idt[14], hwexc_14, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
561     // Interrupt 15 is undefined
562     setgd(&idt[16], hwexc_16, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
563     setgd(&idt[17], hwexc_17, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
564     setgd(&idt[18], hwexc_18, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
565     setgd(&idt[19], hwexc_19, 0, SDT_SYSTGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
566     // Interrupts 20 - 31 are reserved
567
568     /* Load IDT register */
569     __asm volatile("lidt %0" :: "m" (region));
570 }
571 #endif
572
573 /** \brief Initialise private (per-dispatcher) LDT */
574 void ldt_init_disabled(dispatcher_handle_t handle)
575 {
576     errval_t err;
577
578     struct dispatcher_shared_x86_64 *disp =
579         get_dispatcher_shared_x86_64(handle);
580     struct dispatcher_x86_64 *disp_priv = get_dispatcher_x86_64(handle);
581
582     /* setup private (static) LDT, and get kernel to load it */
583     disp->ldt_base = (lvaddr_t) ldt;
584     // XXX: size may not be multiple of page size, but does it really matter?
585     disp->ldt_npages = DIVIDE_ROUND_UP(sizeof(ldt), BASE_PAGE_SIZE);
586 #ifdef ARRAKIS
587     gdt_reset(get_dispatcher_generic(handle));
588     maybe_reload_ldt(disp, true);
589     setup_default_idt();
590 #else
591     sys_x86_reload_ldt();
592 #endif
593
594     /* XXX: kludge to maintain backwards compatibility.
595      * Setup a single segment descriptor that we can use to locate the
596      * current dispatcher (i.e. curdispatcher() always works). This
597      * will be replaced once we switch onto a thread with a real FS segment.
598      */
599     disp_priv->dummyseg[0] = 0;
600     disp_priv->dummyseg[1] = handle;
601     err = ldt_alloc_segment_disabled(handle, disp_priv->dummyseg,
602                                      &disp_priv->disp_seg_selector);
603     if (err_is_fail(err)) {
604         // XXX: can't call usual debug/panic code, as curdispatcher() won't work
605         char buf[128];
606         snprintf(buf, sizeof(buf),
607                  "%.*s.%u: fatal error in ldt_init_disabled(). %s Aborted.\n",
608                  DISP_NAME_LEN, disp->d.name, disp_priv->generic.core_id, err_getstring(err));
609         sys_print(buf, sizeof(buf));
610         while (1) {disp_yield_disabled(handle);}
611     }
612
613     /* load this segment to FS */
614     __asm volatile("mov %%ax, %%fs"
615                    : /* No outputs */
616                    : "a" (disp_priv->disp_seg_selector));
617 }
618
619 /**
620  * \brief Allocate and fill a segment descriptor in the LDT
621  *
622  * \param handle Dispatcher handle
623  * \param segbase Base of segment
624  * \param ret_selector On success, used to return selector for new segment
625  */
626 errval_t ldt_alloc_segment_disabled(dispatcher_handle_t handle, void *segbase,
627                                     uint16_t *ret_selector)
628 {
629     // segment descriptors are limited to a 32-bit base address
630     if ((lvaddr_t)segbase >= (1ul << 32)) {
631         return LIB_ERR_SEGBASE_OVER_4G_LIMIT;
632     }
633
634     // construct descriptor
635     union segment_descriptor desc = {
636         .d = {
637             .lo_base = ((lvaddr_t) segbase) & 0xffffff,
638             .hi_base = (((lvaddr_t) segbase) >> 24) & 0xff,
639             .type = 3, /* read/write data, accessed */
640             .system_desc = 1, /* data */
641             .privilege_level = 3, /* user mode */
642             .present = 1,
643             .long_mode = 0,
644             .operation_size = 1,
645         }
646     };
647
648     // find free LDT entry
649     acquire_spinlock(&ldt_spinlock);
650     for (int i = 0; i < LDT_NENTRIES; i++) {
651         if (!ldt[i].d.present) {
652             ldt[i] = desc;
653             release_spinlock(&ldt_spinlock);
654             assert_disabled(ret_selector != NULL);
655             *ret_selector = X86_64_LDT_SELECTOR(i);
656             return SYS_ERR_OK;
657         }
658     }
659     release_spinlock(&ldt_spinlock);
660
661     return LIB_ERR_LDT_FULL;
662 }
663
664 /**
665  * \brief enabled version of ldt_alloc_segment_disabled()
666  * 
667  * Exposed for calls by special-case software that needs to play with segments.
668  */
669 errval_t ldt_alloc_segment(void *segbase, uint16_t *ret_selector)
670 {
671     dispatcher_handle_t handle = disp_disable();
672     errval_t ret = ldt_alloc_segment_disabled(handle, segbase, ret_selector);
673     disp_enable(handle);
674     return ret;
675 }
676
677 /**
678  * \brief Free a previously-allocated segment on a specific dispatcher
679  *
680  * \param handle Dispatcher handle
681  * \param selector Segment selector
682  */
683 errval_t ldt_free_segment_ondisp(dispatcher_handle_t handle, uint16_t selector)
684 {
685     if ((selector & 0x7) != 7) { // XXX: user-priv LDT selector
686         return LIB_ERR_LDT_SELECTOR_INVALID;
687     }
688
689     int idx = X86_64_SELECTOR_IDX(selector);
690
691     // check that this entry is occupied
692     if (idx >= LDT_NENTRIES || !ldt[idx].d.present) {
693         return LIB_ERR_LDT_SELECTOR_INVALID;
694     }
695
696     // mark entry as free
697     ldt[idx].raw = 0;
698     return SYS_ERR_OK;
699 }
700
701 /**
702  * \brief Free a previously-allocated segment on the current dispatcher
703  *
704  * \param selector Segment selector
705  */
706 errval_t ldt_free_segment(uint16_t selector)
707 {
708     // strictly speaking, we probably don't need to disable here
709     dispatcher_handle_t handle = disp_disable();
710     errval_t ret = ldt_free_segment_ondisp(handle, selector);
711     disp_enable(handle);
712     return ret;
713 }
714
715 /**
716  * \brief Update the base address of a previously-allocated segment
717  *
718  * \param selector Segment selector
719  * \param segbase New base of segment
720  */
721 errval_t ldt_update_segment(uint16_t selector, void *segbase)
722 {
723     if ((selector & 0x7) != 7) { // XXX: user-priv LDT selector
724         return LIB_ERR_LDT_SELECTOR_INVALID;
725     }
726
727     int idx = X86_64_SELECTOR_IDX(selector);
728
729     // check that this entry is occupied
730     if (idx >= LDT_NENTRIES || !ldt[idx].d.present) {
731         return LIB_ERR_LDT_SELECTOR_INVALID;
732     }
733
734     // segment descriptors are limited to a 32-bit base address
735     if ((lvaddr_t)segbase >= (1ul << 32)) {
736         return LIB_ERR_SEGBASE_OVER_4G_LIMIT;
737     }
738
739     // update base address
740     ldt[idx].d.lo_base = ((lvaddr_t) segbase) & 0xffffff;
741     ldt[idx].d.hi_base = (((lvaddr_t) segbase) >> 24) & 0xff;
742
743     return SYS_ERR_OK;
744 }