83c05bcb1e26d5bd8c5cfdf643e9da0ef52480f5
[akaros.git] / kern / arch / i386 / env.c
1 /* See COPYRIGHT for copyright information. */
2 #ifdef __SHARC__
3 #pragma nosharc
4 #endif
5
6 #include <arch/trap.h>
7 #include <env.h>
8 #include <assert.h>
9 #include <pmap.h>
10
11 //
12 // This exits the kernel and starts executing some environment's code.
13 // This function does not return.
14 // Uses 'iret' or 'sysexit' depending on CS.
15 //
16 void env_pop_tf(trapframe_t *tf)
17 {
18         /* Load the LDT for this process.  Slightly ghetto doing it here. */
19         segdesc_t *my_gdt = per_cpu_info[core_id()].gdt;
20         /* using local space so we can use this macro */
21         segdesc_t ldt_temp = SEG_SYS(STS_LDT, (uint32_t)current->env_procdata->ldt,
22                                      8192, 3);
23
24         my_gdt[GD_LDT >> 3] = ldt_temp;
25         asm volatile("lldt %%ax" :: "a"(GD_LDT));
26
27         /* In case they are enabled elsewhere.  We can't take an interrupt in these
28          * routines, due to how they play with the kernel stack pointer. */
29         disable_irq();
30         /*
31          * If the process entered the kernel via sysenter, we need to leave via
32          * sysexit.  sysenter trapframes have 0 for a CS, which is pushed in
33          * sysenter_handler.
34          */
35         if(tf->tf_cs) {
36                 /*
37                  * Restores the register values in the Trapframe with the 'iret'
38                  * instruction.  This exits the kernel and starts executing some
39                  * environment's code.  This function does not return.
40                  */
41                 asm volatile ("movl %0,%%esp;           "
42                               "popal;                   "
43                               "popl %%gs;               "
44                               "popl %%fs;               "
45                               "popl %%es;               "
46                               "popl %%ds;               "
47                               "addl $0x8,%%esp;         "
48                               "iret                     "
49                               : : "g" (tf) : "memory");
50                 panic("iret failed");  /* mostly to placate the compiler */
51         } else {
52                 /* Return path of sysexit.  See sysenter_handler's asm for details.
53                  * One difference is that this tf could be somewhere other than a stack
54                  * (like in a struct proc).  We need to make sure esp is valid once
55                  * interrupts are turned on (which would happen on popfl normally), so
56                  * we need to save and restore a decent esp (the current one).  We need
57                  * a place to save it that is accessible after we change the stack
58                  * pointer to the tf *and* that is specific to this core/instance of
59                  * sysexit.  The simplest and nicest is to use the tf_esp, which we
60                  * can just pop.  Incidentally, the value in oesp would work too.
61                  * To prevent popfl from turning interrupts on, we hack the tf's eflags
62                  * so that we have a chance to change esp to a good value before
63                  * interrupts are enabled.  The other option would be to throw away the
64                  * eflags, but that's less desirable. */
65                 tf->tf_eflags &= !FL_IF;
66                 tf->tf_esp = read_esp();
67                 asm volatile ("movl %0,%%esp;           "
68                               "popal;                   "
69                               "popl %%gs;               "
70                               "popl %%fs;               "
71                               "popl %%es;               "
72                               "popl %%ds;               "
73                               "addl $0x10,%%esp;        "
74                               "popfl;                   "
75                               "movl %%ebp,%%ecx;        "
76                               "movl %%esi,%%edx;        "
77                               "popl %%esp;              "
78                               "sti;                     "
79                               "sysexit                  "
80                               : : "g" (tf) : "memory");
81                 panic("sysexit failed");  /* mostly to placate your mom */
82         }
83 }
84
85 // Flush all mapped pages in the user portion of the address space
86 void
87 env_user_mem_free(env_t* e)
88 {
89         pte_t *pt;
90         uint32_t pdeno, pteno;
91         physaddr_t pa;
92
93         static_assert(UTOP % PTSIZE == 0);
94         for (pdeno = 0; pdeno < PDX(UTOP); pdeno++) {
95
96                 // only look at mapped page tables
97                 if (!(e->env_pgdir[pdeno] & PTE_P))
98                         continue;
99
100                 // find the pa and va of the page table
101                 pa = PTE_ADDR(e->env_pgdir[pdeno]);
102                 pt = (pte_t*COUNT(NPTENTRIES)) KADDR(pa);
103
104                 // unmap all PTEs in this page table 
105                 for (pteno = 0; pteno <= PTX(~0); pteno++) {
106                         if (pt[pteno] & PTE_P)
107                                 page_remove(e->env_pgdir, PGADDR(pdeno, pteno, 0));
108                 }
109
110                 // free the page table itself
111                 e->env_pgdir[pdeno] = 0;
112                 page_decref(pa2page(pa));
113         }
114 }