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;