9041a7d43d56188bf188c50da2e45841d95ad6bd
[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         /*
19          * If the process entered the kernel via sysenter, we need to leave via
20          * sysexit.  sysenter trapframes have 0 for a CS, which is pushed in
21          * sysenter_handler.
22          */
23         if(tf->tf_cs) {
24                 /*
25                  * Restores the register values in the Trapframe with the 'iret'
26                  * instruction.  This exits the kernel and starts executing some
27                  * environment's code.  This function does not return.
28                  */
29                 asm volatile ("movl %0,%%esp;           "
30                               "popal;                   "
31                               "popl %%es;               "
32                               "popl %%ds;               "
33                               "addl $0x8,%%esp;         "
34                               "iret                     "
35                               : : "g" (tf) : "memory");
36                 panic("iret failed");  /* mostly to placate the compiler */
37         } else {
38                 /* Return path of sysexit.  See sysenter_handler's asm for details. */
39                 asm volatile ("movl %0,%%esp;           "
40                               "popal;                   "
41                               "popl %%es;               "
42                               "popl %%ds;               "
43                               "addl $0x10, %%esp;       "
44                               "popfl;                   "
45                               "movl %%ebp, %%ecx;       "
46                               "movl %%esi, %%edx;       "
47                               "sti;                     "
48                               "sysexit                  "
49                               : : "g" (tf) : "memory");
50                 panic("sysexit failed");  /* mostly to placate the compiler */
51         }
52 }
53
54 void
55 env_set_program_counter(env_t* e, uintptr_t pc)
56 {
57         e->env_tf.tf_eip = pc;
58 }
59
60 void
61 env_init_trapframe(trapframe_t *tf)
62 {
63         // Set up appropriate initial values for the segment registers.
64         // GD_UD is the user data segment selector in the GDT, and
65         // GD_UT is the user text segment selector (see inc/memlayout.h).
66         // The low 2 bits of each segment register contains the
67         // Requestor Privilege Level (RPL); 3 means user mode.
68         tf->tf_ds = GD_UD | 3;
69         tf->tf_es = GD_UD | 3;
70         tf->tf_ss = GD_UD | 3;
71         tf->tf_esp = USTACKTOP;
72         tf->tf_cs = GD_UT | 3;
73         // You will set e->env_tf.tf_eip later.
74         // set the env's EFLAGSs to have interrupts enabled
75         tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
76 }
77
78 // Flush all mapped pages in the user portion of the address space
79 void
80 env_user_mem_free(env_t* e)
81 {
82         pte_t *pt;
83         uint32_t pdeno, pteno;
84         physaddr_t pa;
85
86         static_assert(UTOP % PTSIZE == 0);
87         for (pdeno = 0; pdeno < PDX(UTOP); pdeno++) {
88
89                 // only look at mapped page tables
90                 if (!(e->env_pgdir[pdeno] & PTE_P))
91                         continue;
92
93                 // find the pa and va of the page table
94                 pa = PTE_ADDR(e->env_pgdir[pdeno]);
95                 pt = (pte_t*COUNT(NPTENTRIES)) KADDR(pa);
96
97                 // unmap all PTEs in this page table 
98                 for (pteno = 0; pteno <= PTX(~0); pteno++) {
99                         if (pt[pteno] & PTE_P)
100                                 page_remove(e->env_pgdir, PGADDR(pdeno, pteno, 0));
101                 }
102
103                 // free the page table itself
104                 e->env_pgdir[pdeno] = 0;
105                 page_decref(pa2page(pa));
106         }
107 }