2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
36 * Initializes User Memory Management
42 if (syscall_create(SYSCALL_MEM_MALLOC
,memuser_alloc_syscall
,1)==-1) return -1;
43 if (syscall_create(SYSCALL_MEM_FREE
,memuser_free_syscall
,1)==-1) return -1;
44 if (syscall_create(SYSCALL_MEM_GETPHYSADDR
,memuser_getphysaddr_syscall
,1)==-1) return -1;
45 if (syscall_create(SYSCALL_MEM_GETVGA
,memuser_getvga
,1)==-1) return -1;
46 if (syscall_create(SYSCALL_MEM_DMA_ALLOC
,memuser_dma_alloc
,1)==-1) return -1;
47 if (syscall_create(SYSCALL_MEM_DMA_FREE
,memuser_dma_free
,2)==-1) return -1;
48 if (memphys_dma_init()==-1) return -1;
53 * Find a free virtual address
54 * @param addrspace Address space
55 * @param pages Number of pages
56 * @return Address of first page
58 void *memuser_findvirt(addrspace_t
*addrspace
,size_t pages
) {
62 for (virt
= (void*)USERDATA_ADDRESS
;virt
<(void*)USERDATA_ADDRESS
+USERDATA_SIZE
;virt
+=PAGE_SIZE
) {
63 // check if enough pages are found
64 if (found
>=pages
) return virt
-found
*PAGE_SIZE
;
65 if (ADDR2PTE(virt
)==0) {
67 if (!paging_getpde_pd(virt
,addrspace
->pagedir
).exists
) {
69 virt
+= 1023*PAGE_SIZE
;
74 if (paging_getpte_pd(virt
,addrspace
->pagedir
).exists
) found
= 0;
82 * Creates an user pagedir
83 * @return User pagedir
85 pd_t
memuser_create_pagedir() {
86 if (memuser_debug
) kprintf("HELLO\n");
87 pd_t pagedir
= paging_cleanpage(memphys_alloc());
90 paging_physwrite(pagedir
,(void*)PAGEDIR_ADDRESS
,ADDR2PDE(KERNELDATA_ADDRESS
+KERNELDATA_SIZE
));
91 // link last PDE to PD
92 memset(&pde
,0,sizeof(pde
));
93 pde
.page
= ADDR2PAGE(pagedir
);
94 pde
.pagesize
= PGSIZE_4K
;
98 paging_setpde_pd((void*)(4092*MBYTES
),pde
,pagedir
);
103 * Destroys an user pagedir
104 * @param pagedir Pagedir
106 * @todo Check if there are really no user pages left
108 int memuser_destroy_pagedir(pd_t pagedir
) {
109 if (paging_curpd
==pagedir
) paging_loadpagedir(paging_kernelpd
);
110 memphys_free(pagedir
);
115 * Creates an user pagetable
116 * @param addrspace Address space
117 * @param virt Virtual address
120 int memuser_create_pagetable(pd_t pagedir
,void *virt
) {
122 memset(&new,0,sizeof(new));
124 new.page
= ADDR2PAGE(paging_cleanpage(memphys_alloc()));
126 new.pagesize
= PGSIZE_4K
;
130 return paging_setpde_pd(virt
,new,pagedir
)>=0?0:-1;
134 * Creates an address space
135 * @return Address space
137 addrspace_t
*memuser_create_addrspace(proc_t
*proc
) {
138 addrspace_t
*new = malloc(sizeof(addrspace_t
));
140 new->pages_loaded
= llist_create();
141 new->pages_imaginary
= llist_create();
142 new->pages_swapped
= llist_create();
143 new->pagedir
= memuser_create_pagedir();
149 * Destroys an address space
150 * @param addrspace Address space
153 int memuser_destroy_addrspace(addrspace_t
*addrspace
) {
154 if (paging_curpd
!=addrspace
->pagedir
) return -1;
157 if (addrspace
->stack
!=NULL
) memuser_destroy_stack(addrspace
->stack
);
158 while ((page
= llist_pop(addrspace
->pages_loaded
))!=NULL
) memphys_free(paging_unmap(page
));
159 while ((page
= llist_pop(addrspace
->pages_imaginary
))!=NULL
) paging_unmap(page
);
160 while ((page
= llist_pop(addrspace
->pages_swapped
))!=NULL
) swap_remove(addrspace
->proc
,page
);
161 llist_destroy(addrspace
->pages_loaded
);
162 llist_destroy(addrspace
->pages_imaginary
);
163 llist_destroy(addrspace
->pages_swapped
);
164 memuser_destroy_pagedir(addrspace
->pagedir
);
169 * Loads an address space
170 * @param addrspace Address space
173 int memuser_load_addrspace(addrspace_t
*addrspace
) {
174 if (paging_curpd
!=addrspace
->pagedir
) return paging_loadpagedir(addrspace
->pagedir
);
179 * Allocates an user page
180 * @param addrspace Address space
181 * @param count How many bytes to allocated (should be devidable with PAGE_SIZE)
184 void *memuser_alloc(addrspace_t
*addrspace
,size_t count
,int swappable
) {
185 void *addr
= memuser_findvirt(addrspace
,count
/PAGE_SIZE
);
188 for (i
=0;i
<count
/PAGE_SIZE
;i
++) {
189 void *virt
= addr
+i
*PAGE_SIZE
;
190 if (!paging_getpde_pd(virt
,addrspace
->pagedir
).exists
) memuser_create_pagetable(addrspace
->pagedir
,virt
);
192 memset(&pte
,0,sizeof(pte
));
194 pte
.swappable
= swappable
;
198 paging_setpte_pd(virt
,pte
,addrspace
->pagedir
);
199 llist_push(addrspace
->pages_imaginary
,virt
);
206 * Allocates an user page (Syscall)
207 * @param count How many bytes to allocated (should be devidable with PAGE_SIZE)
210 void *memuser_alloc_syscall(size_t count
) {
211 return memuser_alloc(proc_current
->addrspace
,count
,1);
216 * @param addrspace Address space
220 int memuser_free(addrspace_t
*addrspace
,void *page
) {
221 if (page
==NULL
) return 0;
223 pte_t pte
= paging_getpte_pd(addrspace
->stack
,addrspace
->pagedir
);
225 memphys_free(PAGE2ADDR(pte
.page
));
226 llist_remove(addrspace
->pages_loaded
,llist_find(addrspace
->pages_loaded
,page
));
228 else if (pte
.swapped
) {
229 swap_remove(proc_current
,page
);
230 llist_remove(addrspace
->pages_swapped
,llist_find(addrspace
->pages_swapped
,page
));
237 llist_remove(addrspace
->pages_imaginary
,llist_find(addrspace
->pages_imaginary
,page
));
239 memset(&pte
,0,sizeof(pte
));
240 paging_setpte_pd(page
,pte
,addrspace
->pagedir
);
245 * Frees an user page (Syscall)
249 int memuser_free_syscall(void *page
) {
250 return memuser_free(proc_current
->addrspace
,page
);
254 * Gets physical address of a virtual one in specified address space
255 * @param addrspace Address space
256 * @param virt Virtual address
257 * @return Physical address
259 void *memuser_getphysaddr(addrspace_t
*addrspace
,void *virt
) {
260 pte_t pte
= paging_getpte_pd(virt
,addrspace
->pagedir
);
261 if (!pte
.in_memory
) return NULL
;
262 return PAGE2ADDR(pte
.page
);
266 * Gets physical address of a virtual one in specified address space (Syscall)
267 * @param virt Virtual address
268 * @return Physical address
270 void *memuser_getphysaddr_syscall(void *virt
) {
271 return memuser_getphysaddr(proc_current
->addrspace
,virt
);
276 * @param addrspace Address space
277 * @return Stack address
279 void *memuser_create_stack(addrspace_t
*addrspace
) {
280 addrspace
->stack
= memuser_alloc(addrspace
,PAGE_SIZE
,0);
281 if (addrspace
->stack
!=NULL
) return addrspace
->stack
+PAGE_SIZE
-4;
287 * @param addrspace Address space
290 int memuser_destroy_stack(addrspace_t
*addrspace
) {
291 return memuser_free(addrspace
,addrspace
->stack
);
295 * User memory pagefault handler
296 * @param addr Address
297 * @return If Pagefault is a "real" Pagefault
299 int memuser_pagefault(void *addr
) {
300 addrspace_t
*addrspace
= proc_current
->addrspace
;
301 void *page
= PAGEDOWN(addr
);
302 pte_t pte
= paging_getpte(page
);
303 if (!pte
.exists
) return -1;
304 else if (pte
.swapped
&& pte
.in_memory
==0) {
305 kprintf("kernel: Catched access to out-swapped memory\n");
306 if (swap_in(proc_current
,page
)!=-1) {
307 llist_remove(addrspace
->pages_swapped
,llist_find(addrspace
->pages_swapped
,page
));
308 llist_push(addrspace
->pages_loaded
,page
);
309 swap_remove(proc_current
,page
);
314 else if (pte
.cow
&& pte
.in_memory
==1) {
315 void *old
= PAGE2ADDR(pte
.page
);
316 void *new = memphys_alloc();
317 pte
.page
= ADDR2PAGE(new);
320 paging_setpte(page
,pte
);
321 paging_physread(page
,old
,PAGE_SIZE
);
324 else if (pte
.in_memory
==0) {
325 pte
.page
= ADDR2PAGE(memphys_alloc());
327 paging_setpte(page
,pte
);
328 llist_remove(addrspace
->pages_imaginary
,llist_find(addrspace
->pages_imaginary
,page
));
329 llist_push(addrspace
->pages_loaded
,page
);
336 * Allocates a specified page in address space
337 * @param addrspace Address space
338 * @param addr Address to allocate
339 * @param writable If page is writable
342 int memuser_alloc_at(addrspace_t
*addrspace
,void *addr
,void *phys
,int writable
) {
343 if (!paging_getpde_pd(addr
,addrspace
->pagedir
).exists
) {
344 memuser_create_pagetable(addrspace
->pagedir
,addr
);
347 pte_t pte
= paging_getpte_pd(addr
,addrspace
->pagedir
);
348 memset(&pte
,0,sizeof(pte
));
352 pte
.writable
= writable
;
354 if (phys
==NULL
) phys
= memphys_alloc();
355 pte
.page
= ADDR2PAGE(phys
);
356 paging_setpte_pd(addr
,pte
,addrspace
->pagedir
);
357 llist_push(addrspace
->pages_loaded
,addr
);
362 * Syncronize current pagedir with all other pagedirs
364 int memuser_syncpds(void *addr
) {
367 pde_t pde
= paging_getpde(addr
);
369 for (i
=0;(proc
= llist_get(proc_all
,i
));i
++) {
370 memuser_load_addrspace(proc
->addrspace
);
371 paging_setpde(addr
,pde
);
373 if (proc_current
!=NULL
) memuser_load_addrspace(proc_current
->addrspace
);
379 * Maps VGA memory in address space
382 void *memuser_getvga() {
384 if ((virt
= memuser_findvirt(proc_current
->addrspace
,1))) paging_map(virt
,(void*)VGA_TEXT_ADDRESS
,1,proc_current
->gid
==PERM_ROOTGID
);
389 * Allocates DMA memory and maps it into address space (Syscall)
390 * @param size Size of DMA memory
393 void *memuser_dma_alloc(size_t size
) {
394 void *phys
= memphys_dma_alloc(size
/PAGE_SIZE
);
396 void *virt
= memuser_findvirt(proc_current
->addrspace
,size
/PAGE_SIZE
);
399 for (i
=0;i
<size
;i
+=PAGE_SIZE
) {
400 paging_map(virt
+i
,phys
+i
,1,1);
401 //llist_push(proc_current->addrspace->pages_loaded,virt+i);
410 * Unmaps DMA memory and frees it (Syscall)
411 * @param addr DMA memory
412 * @param size Size of DMA memory
414 int memuser_dma_free(void *addr
,size_t size
) {
416 for (i
=0;i
<size
;i
+=PAGE_SIZE
) {
417 //llist_remove(proc_current->addrspace->pages_loaded,llist_find(proc_current->addrspace->pages_loaded,addr));
418 memphys_dma_free(paging_unmap(addr
+i
));