From 08af3f672b032c7fc6f53ee8d18b25001d6cb567 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 21 Mar 2012 23:46:51 +0100 Subject: [PATCH] Kernel: replace vm_contiguous with vm_lookup_range --- kernel/arch/i386/memory.c | 78 ++++++++++++++++------------------ kernel/proto.h | 3 +- kernel/system/do_umap_remote.c | 2 +- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index 7a4e26e7e..9fceb45ac 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -381,7 +381,7 @@ vir_bytes bytes; /* # of bytes to be copied */ /* Now make sure addresses are contiguous in physical memory * so that the umap makes sense. */ - if(bytes > 0 && !vm_contiguous(rp, linear, bytes)) { + if(bytes > 0 && vm_lookup_range(rp, linear, NULL, bytes) != bytes) { printf("umap_virtual: %s: %lu at 0x%lx (vir 0x%lx) not contiguous\n", rp->p_name, bytes, linear, vir_addr); return 0; @@ -453,59 +453,55 @@ PUBLIC int vm_lookup(const struct proc *proc, const vir_bytes virtual, } /*===========================================================================* - * vm_contiguous * + * vm_lookup_range * *===========================================================================*/ -PUBLIC int vm_contiguous(const struct proc *targetproc, vir_bytes vir_buf, size_t bytes) +PUBLIC size_t vm_lookup_range(const struct proc *proc, vir_bytes vir_addr, + phys_bytes *phys_addr, size_t bytes) { - int first = 1, r; - phys_bytes prev_phys = 0; /* Keep lints happy. */ - u32_t po; + /* Look up the physical address corresponding to linear virtual address + * 'vir_addr' for process 'proc'. Return the size of the range covered + * by contiguous physical memory starting from that address; this may + * be anywhere between 0 and 'bytes' inclusive. If the return value is + * nonzero, and 'phys_addr' is non-NULL, 'phys_addr' will be set to the + * base physical address of the range. 'vir_addr' and 'bytes' need not + * be page-aligned, but the caller must have verified that the given + * linear range is valid for the given process at all. + */ + phys_bytes phys, next_phys; + size_t len; - assert(targetproc); + assert(proc); assert(bytes > 0); - if(!HASPT(targetproc)) - return 1; + if (!HASPT(proc)) + return bytes; - /* Start and end at page boundary to make logic simpler. */ - po = vir_buf % I386_PAGE_SIZE; - if(po > 0) { - bytes += po; - vir_buf -= po; - } - po = (vir_buf + bytes) % I386_PAGE_SIZE; - if(po > 0) - bytes += I386_PAGE_SIZE - po; + /* Look up the first page. */ + if (vm_lookup(proc, vir_addr, &phys, NULL) != OK) + return 0; - /* Keep going as long as we cross a page boundary. */ - while(bytes > 0) { - phys_bytes phys; + if (phys_addr != NULL) + *phys_addr = phys; - if((r=vm_lookup(targetproc, vir_buf, &phys, NULL)) != OK) { - printf("vm_contiguous: vm_lookup failed, %d\n", r); - printf("kernel stack: "); - util_stacktrace(); - return 0; - } + len = I386_PAGE_SIZE - (vir_addr % I386_PAGE_SIZE); + vir_addr += len; + next_phys = phys + len; - if(!first) { - if(prev_phys+I386_PAGE_SIZE != phys) { - printf("vm_contiguous: no (0x%lx, 0x%lx)\n", - prev_phys, phys); - printf("kernel stack: "); - util_stacktrace(); - return 0; - } - } + /* Look up any next pages and test physical contiguity. */ + while (len < bytes) { + if (vm_lookup(proc, vir_addr, &phys, NULL) != OK) + break; - first = 0; + if (next_phys != phys) + break; - prev_phys = phys; - vir_buf += I386_PAGE_SIZE; - bytes -= I386_PAGE_SIZE; + len += I386_PAGE_SIZE; + vir_addr += I386_PAGE_SIZE; + next_phys += I386_PAGE_SIZE; } - return 1; + /* We might now have overshot the requested length somewhat. */ + return MIN(bytes, len); } /*===========================================================================* diff --git a/kernel/proto.h b/kernel/proto.h index d70df8174..4ba3328b3 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -207,9 +207,10 @@ _PROTOTYPE( void arch_pre_exec, (struct proc *pr, u32_t, u32_t)); _PROTOTYPE( int arch_umap, (const struct proc *pr, vir_bytes, vir_bytes, int, phys_bytes *)); _PROTOTYPE( int arch_do_vmctl, (message *m_ptr, struct proc *p)); -_PROTOTYPE( int vm_contiguous, (const struct proc *targetproc, vir_bytes vir_buf, size_t count)); _PROTOTYPE( void proc_stacktrace, (struct proc *proc) ); _PROTOTYPE( int vm_lookup, (const struct proc *proc, vir_bytes virtual, phys_bytes *result, u32_t *ptent)); +_PROTOTYPE( size_t vm_lookup_range, (const struct proc *proc, + vir_bytes vir_addr, phys_bytes *phys_addr, size_t bytes) ); _PROTOTYPE( void delivermsg, (struct proc *target)); _PROTOTYPE( void arch_do_syscall, (struct proc *proc) ); _PROTOTYPE( int arch_phys_map, (int index, phys_bytes *addr, diff --git a/kernel/system/do_umap_remote.c b/kernel/system/do_umap_remote.c index 7410f6a2c..99a32c834 100644 --- a/kernel/system/do_umap_remote.c +++ b/kernel/system/do_umap_remote.c @@ -111,7 +111,7 @@ PUBLIC int do_umap_remote(struct proc * caller, message * m_ptr) phys_addr = lin_addr; } - if(vm_running && !vm_contiguous(targetpr, lin_addr, count)) { + if(vm_running && vm_lookup_range(targetpr, lin_addr, NULL, count) != count) { printf("SYSTEM:do_umap: not contiguous\n"); return EFAULT; }