kern
diff src/vm.c @ 43:5f6c5751ae05
- implemented clone_vmem
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 25 Jul 2011 11:29:02 +0300 |
parents | 373a9f50b4e6 |
children | b8f02479e3f4 |
line diff
1.1 --- a/src/vm.c Sun Jul 24 18:29:24 2011 +0300 1.2 +++ b/src/vm.c Mon Jul 25 11:29:02 2011 +0300 1.3 @@ -134,9 +134,10 @@ 1.4 return 0; 1.5 } 1.6 1.7 -void unmap_page(int vpage) 1.8 +int unmap_page(int vpage) 1.9 { 1.10 uint32_t *pgtbl; 1.11 + int res = 0; 1.12 int diridx = PAGE_TO_PGTBL(vpage); 1.13 int pgidx = PAGE_TO_PGTBL_PG(vpage); 1.14 1.15 @@ -157,8 +158,10 @@ 1.16 if(0) { 1.17 err: 1.18 printf("unmap_page(%d): page already not mapped\n", vpage); 1.19 + res = -1; 1.20 } 1.21 set_intr_state(intr_state); 1.22 + return res; 1.23 } 1.24 1.25 /* if ppg_start is -1, we allocate physical pages to map with alloc_phys_page() */ 1.26 @@ -173,6 +176,18 @@ 1.27 return 0; 1.28 } 1.29 1.30 +int unmap_page_range(int vpg_start, int pgcount) 1.31 +{ 1.32 + int i, res = 0; 1.33 + 1.34 + for(i=0; i<pgcount; i++) { 1.35 + if(unmap_page(vpg_start + i) == -1) { 1.36 + res = -1; 1.37 + } 1.38 + } 1.39 + return res; 1.40 +} 1.41 + 1.42 /* if paddr is 0, we allocate physical pages with alloc_phys_page() */ 1.43 int map_mem_range(uint32_t vaddr, size_t sz, uint32_t paddr, unsigned int attr) 1.44 { 1.45 @@ -193,21 +208,39 @@ 1.46 1.47 uint32_t virt_to_phys(uint32_t vaddr) 1.48 { 1.49 + int pg; 1.50 + uint32_t pgaddr; 1.51 + 1.52 + if((pg = virt_to_phys_page(ADDR_TO_PAGE(vaddr))) == -1) { 1.53 + return 0; 1.54 + } 1.55 + pgaddr = PAGE_TO_ADDR(pg); 1.56 + 1.57 + return pgaddr | ADDR_TO_PGOFFS(vaddr); 1.58 +} 1.59 + 1.60 +int virt_to_phys_page(int vpg) 1.61 +{ 1.62 uint32_t pgaddr, *pgtbl; 1.63 - int diridx = ADDR_TO_PGTBL(vaddr); 1.64 - int pgidx = ADDR_TO_PGTBL_PG(vaddr); 1.65 + int diridx, pgidx; 1.66 + 1.67 + if(vpg < 0 || vpg >= PAGE_COUNT) { 1.68 + return -1; 1.69 + } 1.70 + 1.71 + diridx = PAGE_TO_PGTBL(vpg); 1.72 + pgidx = PAGE_TO_PGTBL_PG(vpg); 1.73 1.74 if(!(pgdir[diridx] & PG_PRESENT)) { 1.75 - panic("virt_to_phys(%x): page table %d not present\n", vaddr, diridx); 1.76 + return -1; 1.77 } 1.78 pgtbl = PGTBL(diridx); 1.79 1.80 if(!(pgtbl[pgidx] & PG_PRESENT)) { 1.81 - panic("virt_to_phys(%x): page %d not present\n", vaddr, ADDR_TO_PAGE(vaddr)); 1.82 + return -1; 1.83 } 1.84 pgaddr = pgtbl[pgidx] & PGENT_ADDR_MASK; 1.85 - 1.86 - return pgaddr | ADDR_TO_PGOFFS(vaddr); 1.87 + return ADDR_TO_PAGE(pgaddr); 1.88 } 1.89 1.90 /* allocate a contiguous block of virtual memory pages along with 1.91 @@ -266,9 +299,9 @@ 1.92 disable_intr(); 1.93 1.94 for(i=0; i<num; i++) { 1.95 - uint32_t phys = virt_to_phys(PAGE_TO_ADDR(start + i)); 1.96 - if(phys) { 1.97 - free_phys_page(ADDR_TO_PAGE(phys)); 1.98 + int phys_pg = virt_to_phys_page(start + i); 1.99 + if(phys_pg != -1) { 1.100 + free_phys_page(phys_pg); 1.101 } 1.102 } 1.103 1.104 @@ -393,6 +426,60 @@ 1.105 } 1.106 1.107 1.108 +/* clone_vmem makes a copy of the current page tables, thus duplicating 1.109 + * the virtual address space. 1.110 + * 1.111 + * Returns the physical address of the new page directory. 1.112 + */ 1.113 +uint32_t clone_vmem(void) 1.114 +{ 1.115 + int i, dirpg, tblpg; 1.116 + uint32_t paddr; 1.117 + uint32_t *ndir, *ntbl; 1.118 + 1.119 + if((dirpg = pgalloc(1, MEM_KERNEL)) == -1) { 1.120 + panic("clone_vmem: failed to allocate page directory page\n"); 1.121 + } 1.122 + ndir = (uint32_t*)PAGE_TO_ADDR(dirpg); 1.123 + 1.124 + if((tblpg = pgalloc(1, MEM_KERNEL)) == -1) { 1.125 + panic("clone_vmem: failed to allocate page table page\n"); 1.126 + } 1.127 + ntbl = (uint32_t*)PAGE_TO_ADDR(tblpg); 1.128 + 1.129 + /* we will allocate physical pages and map them to this virtual page 1.130 + * as needed in the loop below. 1.131 + */ 1.132 + free_phys_page(virt_to_phys(tblpg)); 1.133 + 1.134 + for(i=0; i<1024; i++) { 1.135 + if(pgdir[i] & PG_PRESENT) { 1.136 + paddr = alloc_phys_page(); 1.137 + map_page(tblpg, ADDR_TO_PAGE(paddr), 0); 1.138 + 1.139 + /* copy the page table */ 1.140 + memcpy(ntbl, PGTBL(i), PGSIZE); 1.141 + 1.142 + /* set the new page directory entry */ 1.143 + ndir[i] = paddr | (pgdir[i] & PGOFFS_MASK); 1.144 + } else { 1.145 + ndir[i] = 0; 1.146 + } 1.147 + } 1.148 + 1.149 + paddr = virt_to_phys(dirpg); 1.150 + 1.151 + /* unmap before freeing to avoid deallocating the physical pages */ 1.152 + unmap_page(dirpg); 1.153 + unmap_page(tblpg); 1.154 + 1.155 + pgfree(dirpg, 1); 1.156 + pgfree(tblpg, 1); 1.157 + 1.158 + return paddr; 1.159 +} 1.160 + 1.161 + 1.162 void dbg_print_vm(int area) 1.163 { 1.164 struct page_range *node;