Kernel properly handles floating point (XCC)
[akaros.git] / kern / arch / sparc / env.c
1 /* See COPYRIGHT for copyright information. */
2 #ifdef __SHARC__
3 #pragma nosharc
4 #endif
5
6 #ifdef __DEPUTY__
7 #pragma noasync
8 #endif
9
10 #include <trap.h>
11 #include <env.h>
12 #include <assert.h>
13 #include <arch/arch.h>
14 #include <pmap.h>
15
16 void
17 ( env_push_ancillary_state)(env_t* e)
18 {
19         if(e->scp_ctx.hw_tf.psr & PSR_EF)
20                 save_fp_state(&e->env_ancillary_state);
21 }
22
23 void
24 save_fp_state(ancillary_state_t* silly)
25 {
26         #define push_two_fp_regs(pdest,n) \
27             __asm__ __volatile__ ("std  %%f" XSTR(n) ",[%0+4*" XSTR(n) "]" \
28                               : : "r"(pdest) : "memory");
29
30         write_psr(read_psr() | PSR_EF);
31
32         silly->fsr = read_fsr();
33
34         push_two_fp_regs(silly->fpr,0);
35         push_two_fp_regs(silly->fpr,2);
36         push_two_fp_regs(silly->fpr,4);
37         push_two_fp_regs(silly->fpr,6);
38         push_two_fp_regs(silly->fpr,8);
39         push_two_fp_regs(silly->fpr,10);
40         push_two_fp_regs(silly->fpr,12);
41         push_two_fp_regs(silly->fpr,14);
42         push_two_fp_regs(silly->fpr,16);
43         push_two_fp_regs(silly->fpr,18);
44         push_two_fp_regs(silly->fpr,20);
45         push_two_fp_regs(silly->fpr,22);
46         push_two_fp_regs(silly->fpr,24);
47         push_two_fp_regs(silly->fpr,26);
48         push_two_fp_regs(silly->fpr,28);
49         push_two_fp_regs(silly->fpr,30);
50
51         write_psr(read_psr() & ~PSR_EF);
52 }
53
54 void
55 ( env_pop_ancillary_state)(env_t* e)
56
57         if(e->scp_ctx.hw_tf.psr & PSR_EF)
58                 restore_fp_state(&e->env_ancillary_state);
59 }
60
61 void
62 restore_fp_state(ancillary_state_t* silly)
63 {
64         #define pop_two_fp_regs(pdest,n) \
65             __asm__ __volatile__ ("ldd  [%0+4*" XSTR(n) "], %%f" XSTR(n) \
66                               : : "r"(pdest) : "memory");
67
68         write_psr(read_psr() | PSR_EF);
69
70         pop_two_fp_regs(silly->fpr,0);
71         pop_two_fp_regs(silly->fpr,2);
72         pop_two_fp_regs(silly->fpr,4);
73         pop_two_fp_regs(silly->fpr,6);
74         pop_two_fp_regs(silly->fpr,8);
75         pop_two_fp_regs(silly->fpr,10);
76         pop_two_fp_regs(silly->fpr,12);
77         pop_two_fp_regs(silly->fpr,14);
78         pop_two_fp_regs(silly->fpr,16);
79         pop_two_fp_regs(silly->fpr,18);
80         pop_two_fp_regs(silly->fpr,20);
81         pop_two_fp_regs(silly->fpr,22);
82         pop_two_fp_regs(silly->fpr,24);
83         pop_two_fp_regs(silly->fpr,26);
84         pop_two_fp_regs(silly->fpr,28);
85         pop_two_fp_regs(silly->fpr,30);
86
87         write_fsr(silly->fsr);
88
89         write_psr(read_psr() & ~PSR_EF);
90 }
91
92 void init_fp_state(void)
93 {
94         /* TODO: implement me! */
95 }
96
97 // Flush all mapped pages in the user portion of the address space
98 // TODO: only supports L3 user pages
99 int
100 env_user_mem_walk(env_t* e, void* start, size_t len,
101                   mem_walk_callback_t callback, void* arg)
102 {
103         pte_t *l1pt = e->env_pgdir;
104
105         assert((uintptr_t)start % PGSIZE == 0 && len % PGSIZE == 0);
106         void* end = (char*)start+len;
107
108         int l1x_start = L1X(start);
109         int l1x_end = L1X(ROUNDUP(end,L1PGSIZE));
110         for(int l1x = l1x_start; l1x < l1x_end; l1x++)
111         {
112                 if(!(l1pt[l1x] & PTE_PTD))
113                         continue;
114
115                 physaddr_t l2ptpa = PTD_ADDR(l1pt[l1x]);
116                 pte_t* l2pt = (pte_t*)KADDR(l2ptpa);
117
118                 int l2x_start = l1x == l1x_start ? L2X(start) : 0;
119                 int l2x_end = l1x == l1x_end-1 && L2X(ROUNDUP(end,L2PGSIZE)) ?
120                               L2X(ROUNDUP(end,L2PGSIZE)) : NL2ENTRIES;
121                 for(int l2x = l2x_start; l2x < l2x_end; l2x++)
122                 {
123                         if(!(l2pt[l2x] & PTE_PTD))
124                                 continue;
125
126                         physaddr_t l3ptpa = PTD_ADDR(l2pt[l2x]);
127                         pte_t* l3pt = (pte_t*)KADDR(l3ptpa);
128
129                         int l3x_start = l1x == l1x_start && l2x == l2x_start ?
130                                         L3X(start) : 0;
131                         int l3x_end = l1x == l1x_end-1 && l2x == l2x_end-1 && L3X(end) ?
132                                       L3X(end) : NL3ENTRIES;
133                         for(int l3x = l3x_start, ret; l3x < l3x_end; l3x++)
134                                 if(!PAGE_UNMAPPED(l3pt[l3x]))
135                                         if((ret = callback(e,&l3pt[l3x],PGADDR(l1x,l2x,l3x,0),arg)))
136                                                 return ret;
137                 }
138         }
139
140         return 0;
141 }
142
143 void
144 env_pagetable_free(env_t* e)
145 {
146         static_assert(L2X(KERNBASE) == 0 && L3X(KERNBASE) == 0);
147         pte_t *l1pt = e->env_pgdir;
148
149         for(int l1x = 0; l1x < L1X(KERNBASE); l1x++)
150         {
151                 if(!(l1pt[l1x] & PTE_PTD))
152                         continue;
153
154                 physaddr_t l2ptpa = PTD_ADDR(l1pt[l1x]);
155                 pte_t* l2pt = (pte_t*)KADDR(l2ptpa);
156
157                 for(int l2x = 0; l2x < NL2ENTRIES; l2x++)
158                 {
159                         if(!(l2pt[l2x] & PTE_PTD))
160                                 continue;
161
162                         physaddr_t l3ptpa = PTD_ADDR(l2pt[l2x]);
163                         l2pt[l2x] = 0;
164                         page_decref(pa2page(l3ptpa));
165                 }
166
167                 l1pt[l1x] = 0;
168                 page_decref(pa2page(l2ptpa));
169         }
170
171         page_decref(pa2page(e->env_cr3));
172         tlbflush();
173 }