1 /* 2 * Copyright (c) 2006 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/vm/vm_vmspace.c,v 1.2 2006/09/17 21:09:40 dillon Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/kernel.h> 39 #include <sys/systm.h> 40 #include <sys/sysproto.h> 41 #include <sys/mman.h> 42 #include <sys/proc.h> 43 #include <sys/malloc.h> 44 #include <sys/sysctl.h> 45 #include <sys/vkernel.h> 46 47 #include <vm/vm_extern.h> 48 #include <vm/pmap.h> 49 50 static struct vmspace_entry *vkernel_find_vmspace(struct vkernel *vk, void *id); 51 52 static MALLOC_DEFINE(M_VKERNEL, "vkernel", "VKernel structures"); 53 54 /* 55 * vmspace_create (void *id, int type, void *data) 56 * 57 * Create a VMSPACE under the control of the caller with the specified id. 58 * An id of NULL cannot be used. The type and data fields must currently 59 * be 0. 60 * 61 * The vmspace starts out completely empty. Memory may be mapped into the 62 * VMSPACE with vmspace_mmap() and MAP_VPAGETABLE section(s) controlled 63 * with vmspace_mcontrol(). 64 */ 65 int 66 sys_vmspace_create(struct vmspace_create_args *uap) 67 { 68 struct vkernel *vk; 69 struct vmspace_entry *ve; 70 71 if (vkernel_enable == 0) 72 return (EOPNOTSUPP); 73 74 /* 75 * Create a virtual kernel side-structure for the process if one 76 * does not exist. 77 */ 78 if ((vk = curproc->p_vkernel) == NULL) { 79 vk = kmalloc(sizeof(*vk), M_VKERNEL, M_WAITOK|M_ZERO); 80 vk->vk_refs = 1; 81 RB_INIT(&vk->vk_root); 82 curproc->p_vkernel = vk; 83 } 84 85 /* 86 * Create a new VMSPACE 87 */ 88 if (vkernel_find_vmspace(vk, uap->id)) 89 return (EEXIST); 90 ve = kmalloc(sizeof(struct vmspace_entry), M_VKERNEL, M_WAITOK|M_ZERO); 91 ve->vmspace = vmspace_alloc(VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS); 92 ve->id = uap->id; 93 pmap_pinit2(vmspace_pmap(ve->vmspace)); 94 RB_INSERT(vmspace_rb_tree, &vk->vk_root, ve); 95 return (0); 96 } 97 98 /* 99 * vmspace_destroy (void *id) 100 * 101 * Destroy a VMSPACE. 102 */ 103 int 104 sys_vmspace_destroy(struct vmspace_destroy_args *uap) 105 { 106 struct vkernel *vk; 107 struct vmspace_entry *ve; 108 109 if ((vk = curproc->p_vkernel) == NULL) 110 return (EINVAL); 111 if ((ve = vkernel_find_vmspace(vk, uap->id)) == NULL) 112 return (ENOENT); 113 /* XXX check if active */ 114 RB_REMOVE(vmspace_rb_tree, &vk->vk_root, ve); 115 vmspace_free(ve->vmspace); 116 kfree(ve, M_VKERNEL); 117 return(0); 118 } 119 120 /* 121 * vmspace_ctl (void *id, int cmd, void *ctx, int ctx_bytes, int timeout_us) 122 * 123 * Transfer control to a VMSPACE. Control is returned after the specified 124 * number of microseconds or if a page fault, signal, trap, or system call 125 * occurs. 126 */ 127 int 128 sys_vmspace_ctl(struct vmspace_ctl_args *uap) 129 { 130 struct vkernel *vk; 131 struct vmspace_entry *ve; 132 133 if ((vk = curproc->p_vkernel) == NULL) 134 return (EINVAL); 135 if ((ve = vkernel_find_vmspace(vk, uap->id)) == NULL) 136 return (ENOENT); 137 return(EINVAL); 138 } 139 140 /* 141 * vmspace_mmap(id, addr, len, prot, flags, fd, offset) 142 * 143 * map memory within a VMSPACE. This function is just like a normal mmap() 144 * but operates on the vmspace's memory map. Most callers use this to create 145 * a MAP_VPAGETABLE mapping. 146 */ 147 int 148 sys_vmspace_mmap(struct vmspace_mmap_args *uap) 149 { 150 struct vkernel *vk; 151 struct vmspace_entry *ve; 152 153 if ((vk = curproc->p_vkernel) == NULL) 154 return (EINVAL); 155 if ((ve = vkernel_find_vmspace(vk, uap->id)) == NULL) 156 return (ENOENT); 157 return(EINVAL); 158 } 159 160 /* 161 * vmspace_munmap(id, addr, len) 162 * 163 * unmap memory within a VMSPACE. 164 */ 165 int 166 sys_vmspace_munmap(struct vmspace_munmap_args *uap) 167 { 168 struct vkernel *vk; 169 struct vmspace_entry *ve; 170 171 if ((vk = curproc->p_vkernel) == NULL) 172 return (EINVAL); 173 if ((ve = vkernel_find_vmspace(vk, uap->id)) == NULL) 174 return (ENOENT); 175 return(EINVAL); 176 } 177 178 /* 179 * vmspace_mcontrol(id, addr, len, behav, value) 180 * 181 * madvise/mcontrol support for a vmspace. 182 */ 183 int 184 sys_vmspace_mcontrol(struct vmspace_mcontrol_args *uap) 185 { 186 struct vkernel *vk; 187 struct vmspace_entry *ve; 188 vm_offset_t start, end; 189 190 if ((vk = curproc->p_vkernel) == NULL) 191 return (EINVAL); 192 if ((ve = vkernel_find_vmspace(vk, uap->id)) == NULL) 193 return (ENOENT); 194 195 /* 196 * This code is basically copied from sys_mcontrol() 197 */ 198 if (uap->behav < 0 || uap->behav > MADV_CONTROL_END) 199 return (EINVAL); 200 201 if (VM_MAXUSER_ADDRESS > 0 && 202 ((vm_offset_t) uap->addr + uap->len) > VM_MAXUSER_ADDRESS) 203 return (EINVAL); 204 #ifndef i386 205 if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS) 206 return (EINVAL); 207 #endif 208 if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 209 return (EINVAL); 210 211 start = trunc_page((vm_offset_t) uap->addr); 212 end = round_page((vm_offset_t) uap->addr + uap->len); 213 214 return (vm_map_madvise(&ve->vmspace->vm_map, start, end, 215 uap->behav, uap->value)); 216 } 217 218 /* 219 * Red black tree functions 220 */ 221 static int rb_vmspace_compare(struct vmspace_entry *, struct vmspace_entry *); 222 RB_GENERATE(vmspace_rb_tree, vmspace_entry, rb_entry, rb_vmspace_compare); 223 224 /* a->start is address, and the only field has to be initialized */ 225 static int 226 rb_vmspace_compare(struct vmspace_entry *a, struct vmspace_entry *b) 227 { 228 if ((char *)a->id < (char *)b->id) 229 return(-1); 230 else if ((char *)a->id > (char *)b->id) 231 return(1); 232 return(0); 233 } 234 235 static 236 int 237 rb_vmspace_delete(struct vmspace_entry *ve, void *data) 238 { 239 struct vkernel *vk = data; 240 241 RB_REMOVE(vmspace_rb_tree, &vk->vk_root, ve); 242 vmspace_free(ve->vmspace); 243 kfree(ve, M_VKERNEL); 244 return(0); 245 } 246 247 static 248 struct vmspace_entry * 249 vkernel_find_vmspace(struct vkernel *vk, void *id) 250 { 251 struct vmspace_entry *ve; 252 struct vmspace_entry key; 253 254 key.id = id; 255 ve = RB_FIND(vmspace_rb_tree, &vk->vk_root, &key); 256 return (ve); 257 } 258 259 /* 260 * Manage vkernel refs, used by the kernel when fork()ing or exit()ing 261 * a vkernel process. 262 */ 263 void 264 vkernel_hold(struct vkernel *vk) 265 { 266 ++vk->vk_refs; 267 } 268 269 void 270 vkernel_drop(struct vkernel *vk) 271 { 272 KKASSERT(vk->vk_refs > 0); 273 if (--vk->vk_refs == 0) { 274 RB_SCAN(vmspace_rb_tree, &vk->vk_root, NULL, 275 rb_vmspace_delete, vk); 276 kfree(vk, M_VKERNEL); 277 } 278 } 279 280