x86 thread local storage tweaks
[akaros.git] / user / parlib / src / i386 / ldt.c
1 /*
2  * Copyright (c) 2010 The Regents of the University of California
3  * See LICENSE for details.
4  */
5
6 /** @file
7  * @brief x86 LDT init.
8  *
9  * This function is responsible for correctly setting up the the LDT entry for a
10  * given core. This is in support of thread local storage on x86.  x86 expects
11  * the memory at %gs:0x0 to hold the address of the top of the TLS.
12  *
13  * @author Paul Pearce <pearce@eecs.berkeley.edu>
14  * @author Barret Rhoden <brho@eecs.berkeley.edu>
15  */
16
17 #include <ros/common.h>
18 #include <ros/mman.h>
19 #include <arch/mmu.h>
20 #include <parlib.h>
21 #include <hart.h>
22 #include <stdlib.h>
23 #include <assert.h>
24
25 void ldt_init(uint32_t core_id) {
26
27         extern void **tls_array;
28         extern char core0_tls[];
29
30         static void *core0_tls_top_ptr;
31         static bool initialized = 0;
32         void **tls_handle;
33
34         /* mmap in only the LDT that we need.  once the kernel supports un-FIXED
35          * mmap(), we can stop hardcoding the location (USTACKBOT - LDTSIZE) */
36         if (!initialized++) {
37                 procdata.ldt = sys_mmap((void*)USTACKBOT - LDT_SIZE,
38                                         sizeof(segdesc_t) * hart_max_harts(),
39                                         PROT_READ | PROT_WRITE,
40                                         MAP_ANONYMOUS | MAP_FIXED | MAP_POPULATE, 0, 0);
41                 sys_getpid(); // force a kernel crossing to reload the LDT
42                 if (!procdata.ldt) {
43                         debug("Unable to mmap() an LDT!  Exiting...\n");
44                         exit(-EFAIL);
45                 }
46         }
47
48         core0_tls_top_ptr = core0_tls + PARLIB_TLS_SIZE;
49
50         // Get a handle to this core's tls
51         if (core_id == 0) {
52                 tls_handle = &core0_tls_top_ptr;        
53         } else {
54                 tls_handle = &tls_array[core_id];
55         }
56
57         // Build the segment
58         segdesc_t tmp = SEG(STA_W, (uint32_t)tls_handle, (uint32_t)tls_handle + 4, 3);
59
60         // Setup the correct LDT entry for this hart
61         procdata.ldt[core_id] = tmp;
62
63         // Create the GS register.
64         uint32_t gs = (core_id << 3) | 0x07;
65
66         // Set the GS register.
67         asm volatile("movl %0,%%gs" : : "r" (gs));
68
69         // Profit!
70 }