001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019 #include <hwcore/paging.h>
020 #include <hwcore/irq.h>
021
022 #include <sos/assert.h>
023 #include <sos/list.h>
024 #include <sos/klibc.h>
025 #include <sos/physmem.h>
026 #include <sos/kmem_slab.h>
027 #include <sos/kmem_vmm.h>
028
029 #include "mm_context.h"
030
031
032
033
034
035 struct sos_mm_context
036 {
037
038 sos_paddr_t paddr_PD;
039
040
041 sos_vaddr_t vaddr_PD;
042
043
044 sos_ui32_t ref_cnt;
045
046
047 struct sos_mm_context *prev, *next;
048 };
049
050
051
052
053
054 struct sos_kslab_cache * cache_struct_mm_context;
055
056
057
058
059
060
061 static struct sos_mm_context *current_mm_context = NULL;
062
063
064
065
066
067 static struct sos_mm_context *list_mm_context = NULL;
068
069
070
071
072
073 sos_ret_t sos_mm_context_subsystem_setup()
074 {
075 struct sos_mm_context * initial_mm_context;
076 sos_ret_t retval;
077
078
079 cache_struct_mm_context = sos_kmem_cache_create("struct mm_context",
080 sizeof(struct sos_mm_context),
081 1, 0,
082 SOS_KSLAB_CREATE_MAP);
083 if (NULL == cache_struct_mm_context)
084 return -SOS_ENOMEM;
085
086
087
088
089 initial_mm_context
090 = (struct sos_mm_context*) sos_kmem_cache_alloc(cache_struct_mm_context,
091 SOS_KSLAB_ALLOC_ATOMIC);
092 if (NULL == initial_mm_context)
093 return -SOS_ENOMEM;
094
095
096 initial_mm_context->paddr_PD = sos_paging_get_current_PD_paddr();
097
098
099
100
101
102
103 initial_mm_context->vaddr_PD = sos_kmem_vmm_alloc(1, 0);
104 if (initial_mm_context->vaddr_PD == 0)
105 return -SOS_ENOMEM;
106
107
108
109 retval = sos_paging_map(initial_mm_context->paddr_PD,
110 initial_mm_context->vaddr_PD,
111 FALSE,
112 SOS_VM_MAP_PROT_READ
113 | SOS_VM_MAP_PROT_WRITE);
114 if (SOS_OK != retval)
115 return retval;
116
117
118 list_singleton(list_mm_context, initial_mm_context);
119
120
121 initial_mm_context->ref_cnt ++;
122
123
124 initial_mm_context->ref_cnt ++;
125 current_mm_context = initial_mm_context;
126
127 return SOS_OK;
128 }
129
130
131 struct sos_mm_context * sos_mm_context_create(void)
132 {
133 sos_ui32_t flags;
134 struct sos_mm_context *mmctxt;
135
136
137
138
139 mmctxt = (struct sos_mm_context*) sos_kmem_cache_alloc(cache_struct_mm_context, 0);
140 if (NULL == mmctxt)
141 return NULL;
142
143
144 mmctxt->vaddr_PD = sos_kmem_vmm_alloc(1, SOS_KMEM_VMM_MAP);
145 if (mmctxt->vaddr_PD == 0)
146 {
147 sos_kmem_cache_free((sos_vaddr_t) mmctxt);
148 return NULL;
149 }
150
151
152 mmctxt->paddr_PD = sos_paging_get_paddr(mmctxt->vaddr_PD);
153 if (mmctxt->paddr_PD == 0)
154 {
155 sos_kmem_cache_free((sos_vaddr_t) mmctxt);
156 return NULL;
157 }
158
159
160 if (SOS_OK != sos_paging_copy_kernel_space(mmctxt->vaddr_PD,
161 current_mm_context->vaddr_PD))
162 {
163 sos_kmem_cache_free((sos_vaddr_t) mmctxt);
164 return NULL;
165 }
166
167
168 mmctxt->ref_cnt = 1;
169
170
171 sos_disable_IRQs(flags);
172 list_add_tail(list_mm_context, mmctxt);
173 sos_restore_IRQs(flags);
174
175 return mmctxt;
176 }
177
178
179 struct sos_mm_context *
180 sos_mm_context_duplicate(const struct sos_mm_context *model)
181 {
182 struct sos_mm_context *mmctxt;
183
184
185 mmctxt = sos_mm_context_create();
186 if (NULL == mmctxt)
187 return NULL;
188
189
190 if (SOS_OK != sos_paging_copy_user_space(mmctxt->vaddr_PD,
191 model->vaddr_PD))
192 {
193 sos_mm_context_unref(mmctxt);
194 return NULL;
195 }
196
197 return mmctxt;
198 }
199
200
201 sos_ret_t sos_mm_context_unref(struct sos_mm_context *mmctxt)
202 {
203 sos_ui32_t flags;
204
205 sos_disable_IRQs(flags);
206
207
208 SOS_ASSERT_FATAL(mmctxt->ref_cnt > 0);
209
210
211 mmctxt->ref_cnt --;
212
213
214 if (mmctxt->ref_cnt > 0)
215 {
216 sos_restore_IRQs(flags);
217 return SOS_OK;
218 }
219
220
221 SOS_ASSERT_FATAL(mmctxt != current_mm_context);
222
223
224 list_delete(list_mm_context, mmctxt);
225
226 sos_restore_IRQs(flags);
227
228
229 sos_paging_dispose(mmctxt->vaddr_PD);
230
231
232 sos_kmem_vmm_free(mmctxt->vaddr_PD);
233
234 memset(mmctxt, 0x0, sizeof(*mmctxt));
235
236 return SOS_OK;
237 }
238
239
240 sos_ret_t sos_mm_context_ref(struct sos_mm_context *mmctxt)
241 {
242 sos_ui32_t flags;
243
244 sos_disable_IRQs(flags);
245
246
247 SOS_ASSERT_FATAL(mmctxt->ref_cnt > 0);
248
249
250 mmctxt->ref_cnt ++;
251
252 sos_restore_IRQs(flags);
253
254 return SOS_OK;
255 }
256
257
258 sos_ret_t sos_mm_context_switch_to(struct sos_mm_context *mmctxt)
259 {
260 SOS_ASSERT_FATAL(NULL != mmctxt);
261 SOS_ASSERT_FATAL(mmctxt->ref_cnt > 0);
262 SOS_ASSERT_FATAL(current_mm_context->ref_cnt > 0);
263 if (mmctxt != current_mm_context)
264 {
265 sos_ui32_t flags;
266 struct sos_mm_context * prev_mm_context = current_mm_context;
267
268
269
270
271 sos_paging_set_current_PD_paddr(mmctxt->paddr_PD);
272
273
274 current_mm_context = mmctxt;
275
276
277 sos_disable_IRQs(flags);
278 mmctxt->ref_cnt ++;
279 sos_mm_context_unref(prev_mm_context);
280 sos_restore_IRQs(flags);
281 }
282
283 return SOS_OK;
284 }
285
286
287 struct sos_mm_context *get_current_mm_context()
288 {
289 SOS_ASSERT_FATAL(current_mm_context->ref_cnt > 0);
290 return current_mm_context;
291 }
292
293
294
295
296
297
298
299 sos_ret_t sos_mm_context_synch_kernel_PDE(unsigned int index_in_pd,
300 sos_ui32_t pde)
301 {
302 sos_ui32_t flags;
303 struct sos_mm_context * dest_mm_context;
304 int nb_mm_contexts;
305
306 sos_disable_IRQs(flags);
307 list_foreach_forward(list_mm_context, dest_mm_context, nb_mm_contexts)
308 {
309 sos_ui32_t * dest_pd;
310
311 SOS_ASSERT_FATAL(dest_mm_context->ref_cnt > 0);
312
313 dest_pd = (sos_ui32_t*) dest_mm_context->vaddr_PD;
314 dest_pd[index_in_pd] = pde;
315 }
316 sos_restore_IRQs(flags);
317
318 return SOS_OK;
319 }