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>
28 * @return 0=Success; -1=Failure
34 paging_physrw_lastpage
= NULL
;
35 paging_physrw_lastpd
= NULL
;
37 // write initial pagedir
38 paging_kernelpd
= (pd_t
)KERNELPD_ADDRESS
;
39 paging_curpd
= paging_kernelpd
;
40 memset(paging_kernelpd
,0,PAGE_SIZE
);
41 paging_kernelpd
[0].page
= ADDR2PAGE(KERNELPD_ADDRESS
+PAGE_SIZE
);
42 paging_kernelpd
[0].pagesize
= PGSIZE_4K
;
43 paging_kernelpd
[0].user
= 1;
44 paging_kernelpd
[0].writable
= 1;
45 paging_kernelpd
[0].exists
= 1;
46 paging_kernelpd
[1].page
= ADDR2PAGE(KERNELPD_ADDRESS
+PAGE_SIZE
*2);
47 paging_kernelpd
[1].pagesize
= PGSIZE_4K
;
48 paging_kernelpd
[1].user
= 1;
49 paging_kernelpd
[1].writable
= 1;
50 paging_kernelpd
[1].exists
= 1;
51 // write initial pagetables
52 memset((void*)(KERNELPD_ADDRESS
+PAGE_SIZE
),0,PAGE_SIZE
);
53 for (i
=0;i
<KERNELCODE_ADDRESS
+KERNELCODE_SIZE
;i
+=PAGE_SIZE
) {
54 if ((i
>=IVT_ADDRESS
&& i
<IVT_ADDRESS
+IVT_SIZE
) || (i
>=BIOSCODE_ADDRESS
&& i
<BIOSCODE_ADDRESS
+BIOSCODE_SIZE
)) paging_map((void*)i
,(void*)i
,1,0);
55 else paging_map((void*)i
,(void*)i
,0,1);
57 // write second pagetables (maybe needed by stack)
58 memset((void*)(KERNELPD_ADDRESS
+PAGE_SIZE
*2),0,PAGE_SIZE
);
60 // map pagedir as last pagetable
61 memset(paging_kernelpd
+1023,0,sizeof(pde_t
));
62 paging_kernelpd
[1023].page
= ADDR2PAGE(paging_kernelpd
);
63 paging_kernelpd
[1023].pagesize
= PGSIZE_4K
;
64 paging_kernelpd
[1023].user
= 0;
65 paging_kernelpd
[1023].writable
= 1;
66 paging_kernelpd
[1023].exists
= 1;
69 paging_loadpagedir(paging_kernelpd
);
70 asm("mov %cr0,%eax; or $0x80000000,%eax; mov %eax,%cr0;");
81 int paging_loadpagedir(pd_t pd
) {
82 asm("mov %0,%%cr3;"::"a"(pd
));
88 * Reads bytes from physical memory
89 * @param dest Destination for read data
90 * @param src Physical address as source
91 * @param count How many bytes to read
92 * @return How many bytes read
93 * @note Read does not work over page borders
95 int paging_physread(void *dest
,void *src
,size_t count
) {
96 void *src_rounded
= PAGEDOWN(src
);
98 if (src_rounded
!=paging_physrw_lastpage
|| paging_curpd
!=paging_physrw_lastpd
) {
99 if (paging_map((void*)BUFPAGE_ADDRESS
,src_rounded
,0,1)<0) return 0;
100 paging_physrw_lastpage
= src_rounded
;
101 paging_physrw_lastpd
= paging_curpd
;
103 memcpy(dest
,((void*)BUFPAGE_ADDRESS
)+PAGEOFF(src
),count
);
108 * Writes bytes to physical memory
109 * @param dest Physical address as destination
110 * @param src Source of data to write
111 * @param count How many bytes to write
112 * @return How many bytes written
113 * @note Write does not work over page borders
114 * @todo Enable caching
117 int paging_physwrite(void *dest
,void *src
,size_t count
) {
118 void *dest_rounded
= PAGEDOWN(dest
);
120 if (dest_rounded
!=paging_physrw_lastpage
|| paging_curpd
!=paging_physrw_lastpd
|| 1) {
121 if (paging_map((void*)BUFPAGE_ADDRESS
,dest_rounded
,0,1)<0) return 0;
122 paging_physrw_lastpage
= dest_rounded
;
123 paging_physrw_lastpd
= paging_curpd
;
125 memcpy(((void*)BUFPAGE_ADDRESS
)+PAGEOFF(dest
),src
,count
);
131 * @param page Physical address of page
133 void *paging_cleanpage(void *page
) {
134 if (paging_enabled
) {
135 void *page_rounded
= PAGEDOWN(page
);
136 if (page_rounded
!=paging_physrw_lastpage
|| paging_curpd
!=paging_physrw_lastpd
) {
137 if (paging_map((void*)BUFPAGE_ADDRESS
,page_rounded
,0,1)<0) return 0;
138 paging_physrw_lastpage
= page_rounded
;
139 paging_physrw_lastpd
= paging_curpd
;
141 memset((void*)BUFPAGE_ADDRESS
,0,PAGE_SIZE
);
143 else memset(page
,0,PAGE_SIZE
);
149 * @param virt Virtual address
152 pde_t
paging_getpde(void *virt
) {
154 if (paging_enabled
) pde
= ((pd_t
)PAGEDIR_ADDRESS
)[ADDR2PDE(virt
)];
155 else pde
= paging_curpd
[ADDR2PDE(virt
)];
161 * @param virt Virtual address
163 * @return 0=Success; -1=Failure
165 int paging_setpde(void *virt
,pde_t pde
) {
166 if (paging_enabled
) ((pd_t
)PAGEDIR_ADDRESS
)[ADDR2PDE(virt
)] = pde
;
167 else paging_curpd
[ADDR2PDE(virt
)] = pde
;
168 paging_flushtlb(virt
);
174 * @param virt Virtual address
177 pte_t
paging_getpte(void *virt
) {
179 pde_t pde
= paging_getpde(virt
);
180 if (!pde
.exists
) memset(&pte
,0,sizeof(pte
));
182 if (paging_enabled
) pte
= ((pt_t
)(PAGETABLES_ADDRESS
+ADDR2PDE(virt
)*PAGE_SIZE
))[ADDR2PTE(virt
)];
183 else pte
= ((pt_t
)PAGE2ADDR(pde
.page
))[ADDR2PTE(virt
)];
190 * @param virt Virtual address
192 * @return 0=Success; -1=Failure
194 int paging_setpte(void *virt
,pte_t pte
) {
195 pde_t pde
= paging_getpde(virt
);
196 if (!pde
.exists
) return -1;
198 if (paging_enabled
) ((pt_t
)(PAGETABLES_ADDRESS
+ADDR2PDE(virt
)*PAGE_SIZE
))[ADDR2PTE(virt
)] = pte
;
199 else ((pt_t
)PAGE2ADDR(pde
.page
))[ADDR2PTE(virt
)] = pte
;
200 paging_flushtlb(virt
);
206 * Gets a PDE from not-loaded pagedir
207 * @param virt Virtual address
208 * @param pagedir Pagedir
211 pde_t
paging_getpde_pd(void *virt
,pd_t pagedir
) {
212 if (pagedir
==paging_curpd
) return paging_getpde(virt
);
215 paging_physread(&pde
,pagedir
+ADDR2PDE(virt
),sizeof(pde
));
221 * Sets a PDE in a not-loaded pagedir
222 * @param virt Virtual address
225 * @return 0=Success; -1=Failure
227 int paging_setpde_pd(void *virt
,pde_t pde
,pd_t pagedir
) {
228 if (pagedir
==paging_curpd
) return paging_setpde(virt
,pde
);
229 else return paging_physwrite(pagedir
+ADDR2PDE(virt
),&pde
,sizeof(pde
))==sizeof(pde
)?0:-1;
233 * Gets a PTE from not-loaded pagedir
234 * @param virt Virtual address
235 * @param pagedir Pagedir
238 pte_t
paging_getpte_pd(void *virt
,pd_t pagedir
) {
239 if (pagedir
==paging_curpd
) return paging_getpte(virt
);
241 pt_t pt
= PAGE2ADDR(paging_getpde_pd(virt
,pagedir
).page
);
243 if (pt
==NULL
) memset(&pte
,0,sizeof(pte
));
244 else paging_physread(&pte
,pt
+ADDR2PTE(virt
),sizeof(pte
));
250 * Sets a PTE in a not-loaded pagedir
251 * @param virt Virtual address
254 * @return 0=Success; -1=Failure
256 int paging_setpte_pd(void *virt
,pte_t pte
,pd_t pagedir
) {
257 if (pagedir
==paging_curpd
) return paging_setpte(virt
,pte
);
259 pt_t pt
= PAGE2ADDR(paging_getpde_pd(virt
,pagedir
).page
);
260 int ret
= paging_physwrite(pt
+ADDR2PTE(virt
),&pte
,sizeof(pte
))==sizeof(pte
)?0:-1;
261 paging_flushtlb(virt
);
267 * Maps a page (extended)
268 * @param virt Virtual address
269 * @param phys Physical address
270 * @param user Whether page is accessable by user
271 * @param writable Whether page is writable
272 * @param swappable Whether page is swappable
273 * @param cow Whether page is COW
274 * @param pagedir Pagedir to do mapping in
275 * @return 0=Success; -1=Failure
277 int paging_map_pd(void *virt
,void *phys
,int user
,int writable
,int swappable
,int cow
,pd_t pagedir
) {
278 if (!paging_getpde_pd(virt
,pagedir
).exists
) {
279 pt_t pagetable
= (pt_t
)(PAGETABLES_ADDRESS
+ADDR2PDE(virt
)*PAGE_SIZE
);
281 memset(&new,0,sizeof(new));
282 new.page
= ADDR2PAGE(memphys_alloc());
283 new.pagesize
= PGSIZE_4K
;
287 if (paging_setpde_pd(virt
,new,pagedir
)<0) return -1;
288 paging_flushtlb(pagetable
);
289 memset(pagetable
,0,PAGE_SIZE
);
290 if (pagedir
!=paging_curpd
) kprintf("kernel: new pagetable\n");
293 memset(&new,0,sizeof(new));
294 new.page
= ADDR2PAGE(phys
);
297 new.writable
= writable
?1:0;
299 new.swappable
= swappable
;
301 if (paging_setpte_pd(virt
,new,pagedir
)<0) return -1;
302 if (pagedir
!=paging_curpd
) {
303 kprintf("kernel: mapped 0x%x to 0x%x\n",virt
,PAGE2ADDR(new.page
));
309 * Unmaps a page and returns physical address of it
310 * @param virt Virtual address
311 * @return Physical address
313 void *paging_unmap(void *virt
) {
314 void *addr
= PAGE2ADDR(paging_getpte(virt
).page
);
316 if (!pte
.in_memory
) addr
= NULL
;
317 memset(&pte
,0,sizeof(pte
));
318 paging_setpte(virt
,pte
);
323 * Gets physical address
324 * @param virt Virtual address
325 * @return Physical address
327 void *paging_getphysaddr(void *virt
) {
328 pte_t pte
= paging_getpte(virt
);
329 if (pte
.exists
&& pte
.in_memory
) return PAGE2ADDR(pte
.page
)+PAGEOFF(virt
);