Subject: Re: kqmemu: uvm(9) questions
To: None <tech-kern@netbsd.org>
From: Tobias Nygren <tnn@NetBSD.org>
List: tech-kern
Date: 04/25/2007 09:45:56
Oliver Gould wrote:
> Hello-
>
> More questions.. this time about uvm(9)
>
> KQEMU wants to allocate kernel memory, and then be able to wire and
> unwire it.
>
> FreeBSD's implementation looks something like:
>
>   struct kqemu_page *CDECL kqemu_alloc_zeroed_page(unsigned long *ppage_index)
>   {
>       pmap_t pmap;
>       vm_offset_t va;
>       vm_paddr_t pa;
>   
>       va = kmem_alloc(kernel_map, PAGE_SIZE);
>       if (va == 0) {
>           kqemu_log("kqemu_alloc_zeroed_page: NULL\n");
>           return NULL;
>       }
>       pmap = vm_map_pmap(kernel_map);
>       pa = pmap_extract(pmap, va);
>       /* kqemu_log("kqemu_alloc_zeroed_page: %08x\n", pa); */
>       *ppage_index = pa >> PAGE_SHIFT;
>       return (struct kqemu_page *)va;
>   }
>
>   struct kqemu_user_page *CDECL kqemu_lock_user_page(unsigned long *ppage_index,
>                                                    unsigned long user_addr)
>   {
>       struct vmspace *vm = curproc->p_vmspace;
>       vm_offset_t va = user_addr;
>       vm_paddr_t pa = 0;
>       int ret;
>       pmap_t pmap;
>   #if __FreeBSD_version >= 500000
>       ret = vm_map_wire(&vm->vm_map, va, va+PAGE_SIZE, VM_MAP_WIRE_USER);
>   #else
>       ret = vm_map_user_pageable(&vm->vm_map, va, va+PAGE_SIZE, FALSE);
>   #endif
>       if (ret != KERN_SUCCESS) {
>           kqemu_log("kqemu_lock_user_page(%08lx) failed, ret=%d\n", user_addr, ret);
>           return NULL;
>       }
>       pmap = vm_map_pmap(&vm->vm_map);
>       pa = pmap_extract(pmap, va);
>       *ppage_index = pa >> PAGE_SHIFT;
>       return (struct kqemu_user_page *)va;
>   }
>
> My (thusfar disfunctional) port looks like:
>
>   struct kqemu_page *
>   kqemu_alloc_zeroed_page(unsigned long *ppage_index)
>   {
> 	extern  struct vm_map *kernel_map;
>        	pmap_t  pmap;
>        	vaddr_t va;
>        	paddr_t pa;
>
>        	pa = 0;
> 	va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
> 	if (va == 0) {
> 		kqemu_log(...);
> 		return NULL;
> 	}
> 	pmap = vm_map_pmap(kernel_map);
> 	if (pmap_extract(pmap, va, &pa) == FALSE) {
> 		kqemu_log(...);
> 		return NULL;
> 	}
> 	if (kqemu_debug > 0)
> 		kqemu_log("kqemu_alloc_zeroed_page: va=%08x pa=%08x\n",
> 			va, pa);
>
> 	*ppage_index = pa >> PAGE_SHIFT;
> 	return (struct kqemu_page *)va;
>   }
>
>   struct kqemu_user_page *
>   kqemu_lock_user_page(unsigned long *ppage_index, unsigned long user_addr)
>   {
>         struct  vmspace *vm;
>         vaddr_t va;
>         paddr_t pa;
>         pmap_t  pmap;
>
>         vm = curproc->p_vmspace;
>         va = (vaddr_t)user_addr;
>         pa = 0;
>         /* FIXME - fails */
>         if (uvm_map_pageable(&vm->vm_map, va, va+PAGE_SIZE,
>                                 FALSE, 0) == FALSE) {
>                 kqemu_log("kqemu_lock_user_page(%08lx) failed\n", va);
>                 return NULL;
>         }
>         pmap = vm_map_pmap(&vm->vm_map);
>         if (pmap_extract(pmap, va, &pa) == FALSE) {
>                 kqemu_log(...);
>                 return NULL;
>         }
>         *ppage_index = pa >> PAGE_SHIFT;
>         return (struct kqemu_user_page *)va;
>   }
>
> The issue is that uvm_map_pageable(9) fails in kqemu_lock_user_page():
>
>   Apr 24 18:58:12 isla /netbsd: kqemu: kqemu_alloc_zeroed_page:
> 	  va=d49e0000 pa=24c95000
>   Apr 24 18:58:12 isla /netbsd: kqemu: kqemu_alloc_zeroed_page:
> 	  va=d49e1000 pa=260d6000
>   Apr 24 18:58:12 isla /netbsd: kqemu: kqemu_lock_user_page(b305d000) failed
>  
> If I put an equivalent statement in kqemu_alloc_zeroed_page() directly
> following uvm_km_alloc(), it succeeds.
>
> My current thought is that the vm_map is the culprit here.  From a
> recent thread, I gather that 'kernel_map' should not be used (my use of
> it is inherited from FreeBSD's code).  Does it seem likely that this is
> the issue?  What else should I consider?
>
> Also, is there any documentation that describes, in a high-level way,
> how uvm(9) works?  The Internals Guide is woefully incomplete, and I
> would imagine that would be the proper place for such documentation.
>
> And, on a procedural note, is it bothersome for me to post this much
> code in email?  I'd hate to put anyone off.
>
> Many thanks,
>   - Oliver
>   
 
Not sure why it fails, but I had this wiring stuff working awhile ago on 
3.99.x, see:

http://cvsweb.netbsd.se/cgi-bin/bsdweb.cgi/~checkout~/wip/qemu-qvm86/files/Attic/qvm86-netbsd.c?rev=1.1.1.1;content-type=text%2Fplain

-Tobias