PCI device locking and synchronization
[akaros.git] / kern / arch / x86 / process32.c
1 #include <arch/arch.h>
2 #include <trap.h>
3 #include <process.h>
4 #include <pmap.h>
5 #include <smp.h>
6
7 #include <string.h>
8 #include <assert.h>
9 #include <stdio.h>
10
11 /* TODO: handle user and kernel contexts */
12 void proc_pop_ctx(struct user_context *ctx)
13 {
14         struct hw_trapframe *tf = &ctx->tf.hw_tf;
15         assert(ctx->type == ROS_HW_CTX);
16
17         /* Bug with this whole idea (TODO: (TLSV))*/
18         /* Load the LDT for this process.  Slightly ghetto doing it here. */
19         /* copy-in and check the LDT location.  the segmentation hardware writes the
20          * accessed bit, so we want the memory to be in the user-writeable area. */
21         segdesc_t *ldt = current->procdata->ldt;
22         ldt = (segdesc_t*)MIN((uintptr_t)ldt, UWLIM - LDT_SIZE);
23         /* Only set up the ldt if a pointer to the ldt actually exists */
24         if(ldt != NULL) {
25                 segdesc_t *my_gdt = per_cpu_info[core_id()].gdt;
26                 segdesc_t ldt_temp = SEG_SYS(STS_LDT, (uint32_t)ldt, LDT_SIZE, 3);
27                 my_gdt[GD_LDT >> 3] = ldt_temp;
28                 asm volatile("lldt %%ax" :: "a"(GD_LDT));
29         }
30
31         /* In case they are enabled elsewhere.  We can't take an interrupt in these
32          * routines, due to how they play with the kernel stack pointer. */
33         disable_irq();
34         /*
35          * If the process entered the kernel via sysenter, we need to leave via
36          * sysexit.  sysenter trapframes have 0 for a CS, which is pushed in
37          * sysenter_handler.
38          */
39         if(tf->tf_cs) {
40                 /*
41                  * Restores the register values in the Trapframe with the 'iret'
42                  * instruction.  This exits the kernel and starts executing some
43                  * environment's code.  This function does not return.
44                  */
45                 asm volatile ("movl %0,%%esp;           "
46                               "popal;                   "
47                               "popl %%gs;               "
48                               "popl %%fs;               "
49                               "popl %%es;               "
50                               "popl %%ds;               "
51                               "addl $0x8,%%esp;         "
52                               "iret                     "
53                               : : "g" (tf) : "memory");
54                 panic("iret failed");  /* mostly to placate the compiler */
55         } else {
56                 /* Return path of sysexit.  See sysenter_handler's asm for details.
57                  * One difference is that this tf could be somewhere other than a stack
58                  * (like in a struct proc).  We need to make sure esp is valid once
59                  * interrupts are turned on (which would happen on popfl normally), so
60                  * we need to save and restore a decent esp (the current one).  We need
61                  * a place to save it that is accessible after we change the stack
62                  * pointer to the tf *and* that is specific to this core/instance of
63                  * sysexit.  The simplest and nicest is to use the tf_esp, which we
64                  * can just pop.  Incidentally, the value in oesp would work too.
65                  * To prevent popfl from turning interrupts on, we hack the tf's eflags
66                  * so that we have a chance to change esp to a good value before
67                  * interrupts are enabled.  The other option would be to throw away the
68                  * eflags, but that's less desirable. */
69                 tf->tf_eflags &= !FL_IF;
70                 tf->tf_esp = read_sp();
71                 asm volatile ("movl %0,%%esp;           "
72                               "popal;                   "
73                               "popl %%gs;               "
74                               "popl %%fs;               "
75                               "popl %%es;               "
76                               "popl %%ds;               "
77                               "addl $0x10,%%esp;        "
78                               "popfl;                   "
79                               "movl %%ebp,%%ecx;        "
80                               "popl %%esp;              "
81                               "sti;                     "
82                               "sysexit                  "
83                               : : "g" (tf) : "memory");
84                 panic("sysexit failed");  /* mostly to placate your mom */
85         }
86 }
87
88 /* TODO: consider using a SW context */
89 void proc_init_ctx(struct user_context *ctx, uint32_t vcoreid, uintptr_t entryp,
90                    uintptr_t stack_top, uintptr_t tls_desc)
91 {
92         struct hw_trapframe *tf = &ctx->tf.hw_tf;
93         ctx->type = ROS_HW_CTX;
94
95         memset(tf,0,sizeof(*tf));
96
97         /* Set up appropriate initial values for the segment registers.
98          * GD_UD is the user data segment selector in the GDT, and
99          * GD_UT is the user text segment selector (see inc/memlayout.h).
100          * The low 2 bits of each segment register contains the
101          * Requestor Privilege Level (RPL); 3 means user mode. */
102         tf->tf_ds = GD_UD | 3;
103         tf->tf_es = GD_UD | 3;
104         tf->tf_ss = GD_UD | 3;
105         tf->tf_esp = stack_top-64;
106         tf->tf_cs = GD_UT | 3;
107         /* set the env's EFLAGSs to have interrupts enabled */
108         tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
109
110         tf->tf_eip = entryp;
111
112         /* Coupled closely with user's entry.S.  id is the vcoreid, which entry.S
113          * uses to determine what to do.  vcoreid == 0 is the main core/context. */
114         tf->tf_regs.reg_eax = vcoreid;
115         /* Note we don't pass the tlsdesc.  32 bit TLS is pretty jacked up, so we
116          * let userspace deal with it. TODO: (TLSV) */
117 }
118
119 /* TODO: handle both HW and SW contexts */
120 void proc_secure_ctx(struct user_context *ctx)
121 {
122         struct hw_trapframe *tf = &ctx->tf.hw_tf;
123         ctx->type = ROS_HW_CTX;
124         /* we normally don't need to set the non-CS regs, but they could be
125          * gibberish and cause a GPF.  gs can still be gibberish, but we don't
126          * necessarily know what it ought to be (we could check, but that's a pain).
127          * the code protecting the kernel from TLS related things ought to be able
128          * to handle GPFs on popping gs. TODO: (TLSV) */
129         tf->tf_ds = GD_UD | 3;
130         tf->tf_es = GD_UD | 3;
131         tf->tf_fs = 0;
132         //tf->tf_gs = whatevs.  ignoring this.
133         tf->tf_ss = GD_UD | 3;
134         tf->tf_cs ? GD_UT | 3 : 0; // can be 0 for sysenter TFs.
135         tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
136 }
137
138 /* Called when we are currently running an address space on our core and want to
139  * abandon it.  We need a known good pgdir before releasing the old one.  We
140  * decref, since current no longer tracks the proc (and current no longer
141  * protects the cr3).  We also need to clear out the TLS registers (before
142  * unmapping the address space!) */
143 void __abandon_core(void)
144 {
145         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
146         asm volatile ("movw %%ax,%%gs; lldt %%ax" :: "a"(0));
147         lcr3(boot_cr3);
148         proc_decref(pcpui->cur_proc);
149         pcpui->cur_proc = 0;
150 }