diff options
author | Robert Morris <[email protected]> | 2010-09-27 16:14:33 -0400 |
---|---|---|
committer | Robert Morris <[email protected]> | 2010-09-27 16:14:33 -0400 |
commit | 4655d42e3b65f906eae8c815fb78331790f6e423 (patch) | |
tree | de5b3e4e74c992fd3cd8fef0a2d37cb805c659ac /vm.c | |
parent | a9183883b88bfccd1c6a62e27621b2c892d50b67 (diff) | |
download | xv6-labs-4655d42e3b65f906eae8c815fb78331790f6e423.tar.gz xv6-labs-4655d42e3b65f906eae8c815fb78331790f6e423.tar.bz2 xv6-labs-4655d42e3b65f906eae8c815fb78331790f6e423.zip |
copyout() copies data to a va in a pagetable, for exec() &c
usertest that passes too many arguments, break exec
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 32 |
1 files changed, 28 insertions, 4 deletions
@@ -6,8 +6,6 @@ #include "proc.h" #include "elf.h" -#define USERTOP 0xA0000 - static pde_t *kpgdir; // for use in scheduler() // Set up CPU's kernel segment descriptors. @@ -126,7 +124,7 @@ setupkvm(void) { pde_t *pgdir; extern char etext[]; - char *rwstart = PGROUNDDOWN(etext) - PGSIZE; + char *rwstart = PGROUNDDOWN(etext); uint rwlen = (uint)rwstart - 0x100000; // Allocate page directory @@ -193,7 +191,10 @@ char* uva2ka(pde_t *pgdir, char *uva) { pte_t *pte = walkpgdir(pgdir, uva, 0); - if(pte == 0) return 0; + if((*pte & PTE_P) == 0) + return 0; + if((*pte & PTE_U) == 0) + return 0; uint pa = PTE_ADDR(*pte); return (char *)pa; } @@ -326,3 +327,26 @@ bad: return 0; } +// copy some data to user address va in page table pgdir. +// most useful when pgdir is not the current page table. +// returns 1 if everthing OK, 0 on error. +// uva2ka ensures this only works for PTE_U pages. +int +copyout(pde_t *pgdir, uint va, void *xbuf, uint len) +{ + char *buf = (char *) xbuf; + while(len > 0){ + uint va0 = (uint)PGROUNDDOWN(va); + char *pa0 = uva2ka(pgdir, (char*) va0); + if(pa0 == 0) + return 0; + uint n = PGSIZE - (va - va0); + if(n > len) + n = len; + memmove(pa0 + (va - va0), buf, n); + len -= n; + buf += n; + va = va0 + PGSIZE; + } + return 1; +} |