1 2 #define _SYSTEM 1 3 4 #include <minix/callnr.h> 5 #include <minix/com.h> 6 #include <minix/config.h> 7 #include <minix/const.h> 8 #include <minix/ds.h> 9 #include <minix/endpoint.h> 10 #include <minix/minlib.h> 11 #include <minix/type.h> 12 #include <minix/ipc.h> 13 #include <minix/sysutil.h> 14 #include <minix/syslib.h> 15 #include <minix/safecopies.h> 16 #include <minix/bitmap.h> 17 #include <minix/debug.h> 18 19 #include <machine/vmparam.h> 20 21 #include <sys/mman.h> 22 #include <sys/param.h> 23 24 #include <errno.h> 25 #include <assert.h> 26 #include <string.h> 27 #include <env.h> 28 #include <stdio.h> 29 #include <fcntl.h> 30 31 #include "glo.h" 32 #include "proto.h" 33 #include "util.h" 34 #include "region.h" 35 36 37 static struct vir_region *mmap_region(struct vmproc *vmp, vir_bytes addr, 38 u32_t vmm_flags, size_t len, u32_t vrflags, 39 mem_type_t *mt, int execpriv) 40 { 41 u32_t mfflags = 0; 42 struct vir_region *vr = NULL; 43 44 if(vmm_flags & MAP_LOWER16M) vrflags |= VR_LOWER16MB; 45 if(vmm_flags & MAP_LOWER1M) vrflags |= VR_LOWER1MB; 46 if(vmm_flags & MAP_ALIGNMENT_64KB) vrflags |= VR_PHYS64K; 47 if(vmm_flags & MAP_PREALLOC) mfflags |= MF_PREALLOC; 48 if(vmm_flags & MAP_UNINITIALIZED) { 49 if(!execpriv) return NULL; 50 vrflags |= VR_UNINITIALIZED; 51 } 52 53 if(len <= 0) { 54 return NULL; 55 } 56 57 if(len % VM_PAGE_SIZE) 58 len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); 59 60 if (addr && (vmm_flags & MAP_FIXED)) { 61 int r = map_unmap_range(vmp, addr, len); 62 if(r != OK) { 63 printf("mmap_region: map_unmap_range failed (%d)\n", r); 64 return NULL; 65 } 66 } 67 68 if (addr || (vmm_flags & MAP_FIXED)) { 69 /* An address is given, first try at that address. */ 70 vr = map_page_region(vmp, addr, 0, len, 71 vrflags, mfflags, mt); 72 if(!vr && (vmm_flags & MAP_FIXED)) 73 return NULL; 74 } 75 76 if (!vr) { 77 /* No address given or address already in use. */ 78 vr = map_page_region(vmp, VM_MMAPBASE, VM_MMAPTOP, len, 79 vrflags, mfflags, mt); 80 } 81 82 return vr; 83 } 84 85 static int mmap_file(struct vmproc *vmp, 86 int vmfd, off_t file_offset, int flags, 87 ino_t ino, dev_t dev, u64_t filesize, vir_bytes addr, vir_bytes len, 88 vir_bytes *retaddr, u16_t clearend, int writable, int mayclosefd) 89 { 90 /* VFS has replied to a VMVFSREQ_FDLOOKUP request. */ 91 struct vir_region *vr; 92 u64_t page_offset; 93 int result = OK; 94 u32_t vrflags = 0; 95 96 if(writable) vrflags |= VR_WRITABLE; 97 98 /* Do some page alignments. */ 99 if((page_offset = (file_offset % VM_PAGE_SIZE))) { 100 file_offset -= page_offset; 101 len += page_offset; 102 } 103 104 len = roundup(len, VM_PAGE_SIZE); 105 106 /* All numbers should be page-aligned now. */ 107 assert(!(len % VM_PAGE_SIZE)); 108 assert(!(filesize % VM_PAGE_SIZE)); 109 assert(!(file_offset % VM_PAGE_SIZE)); 110 111 #if 0 112 /* XXX ld.so relies on longer-than-file mapping */ 113 if((u64_t) len + file_offset > filesize) { 114 printf("VM: truncating mmap dev 0x%x ino %d beyond file size in %d; offset %llu, len %lu, size %llu; ", 115 dev, ino, vmp->vm_endpoint, 116 file_offset, len, filesize); 117 len = filesize - file_offset; 118 return EINVAL; 119 } 120 #endif 121 122 if(!(vr = mmap_region(vmp, addr, flags, len, 123 vrflags, &mem_type_mappedfile, 0))) { 124 result = ENOMEM; 125 } else { 126 *retaddr = vr->vaddr + page_offset; 127 result = OK; 128 129 mappedfile_setfile(vmp, vr, vmfd, 130 file_offset, dev, ino, clearend, 1, mayclosefd); 131 } 132 133 return result; 134 } 135 136 int do_vfs_mmap(message *m) 137 { 138 vir_bytes v; 139 struct vmproc *vmp; 140 int r, n; 141 u16_t clearend, flags = 0; 142 143 /* It might be disabled */ 144 if(!enable_filemap) return ENXIO; 145 146 clearend = m->m_vm_vfs_mmap.clearend; 147 flags = m->m_vm_vfs_mmap.flags; 148 149 if((r=vm_isokendpt(m->m_vm_vfs_mmap.who, &n)) != OK) 150 panic("bad ep %d from vfs", m->m_vm_vfs_mmap.who); 151 vmp = &vmproc[n]; 152 153 return mmap_file(vmp, m->m_vm_vfs_mmap.fd, m->m_vm_vfs_mmap.offset, 154 MAP_PRIVATE | MAP_FIXED, 155 m->m_vm_vfs_mmap.ino, m->m_vm_vfs_mmap.dev, 156 (u64_t) LONG_MAX * VM_PAGE_SIZE, 157 m->m_vm_vfs_mmap.vaddr, m->m_vm_vfs_mmap.len, &v, 158 clearend, flags, 0); 159 } 160 161 static void mmap_file_cont(struct vmproc *vmp, message *replymsg, void *cbarg, 162 void *origmsg_v) 163 { 164 message *origmsg = (message *) origmsg_v; 165 message mmap_reply; 166 int result; 167 int writable = 0; 168 vir_bytes v = (vir_bytes) MAP_FAILED; 169 170 if(origmsg->m_mmap.prot & PROT_WRITE) 171 writable = 1; 172 173 if(replymsg->VMV_RESULT != OK) { 174 #if 0 /* Noisy diagnostic for mmap() by ld.so */ 175 printf("VM: VFS reply failed (%d)\n", replymsg->VMV_RESULT); 176 sys_diagctl_stacktrace(vmp->vm_endpoint); 177 #endif 178 result = replymsg->VMV_RESULT; 179 } else { 180 /* Finish mmap */ 181 result = mmap_file(vmp, replymsg->VMV_FD, origmsg->m_mmap.offset, 182 origmsg->m_mmap.flags, 183 replymsg->VMV_INO, replymsg->VMV_DEV, 184 (u64_t) replymsg->VMV_SIZE_PAGES*PAGE_SIZE, 185 (vir_bytes) origmsg->m_mmap.addr, 186 origmsg->m_mmap.len, &v, 0, writable, 1); 187 } 188 189 /* Unblock requesting process. */ 190 memset(&mmap_reply, 0, sizeof(mmap_reply)); 191 mmap_reply.m_type = result; 192 mmap_reply.m_mmap.retaddr = (void *) v; 193 194 if(ipc_send(vmp->vm_endpoint, &mmap_reply) != OK) 195 panic("VM: mmap_file_cont: ipc_send() failed"); 196 } 197 198 /*===========================================================================* 199 * do_mmap * 200 *===========================================================================*/ 201 int do_mmap(message *m) 202 { 203 int r, n; 204 struct vmproc *vmp; 205 vir_bytes addr = (vir_bytes) m->m_mmap.addr; 206 struct vir_region *vr = NULL; 207 int execpriv = 0; 208 size_t len = (vir_bytes) m->m_mmap.len; 209 210 /* RS and VFS can do slightly more special mmap() things */ 211 if(m->m_source == VFS_PROC_NR || m->m_source == RS_PROC_NR) 212 execpriv = 1; 213 214 if(m->m_mmap.flags & MAP_THIRDPARTY) { 215 if(!execpriv) return EPERM; 216 if((r=vm_isokendpt(m->m_mmap.forwhom, &n)) != OK) 217 return ESRCH; 218 } else { 219 /* regular mmap, i.e. for caller */ 220 if((r=vm_isokendpt(m->m_source, &n)) != OK) { 221 panic("do_mmap: message from strange source: %d", 222 m->m_source); 223 } 224 } 225 226 vmp = &vmproc[n]; 227 228 /* "SUSv3 specifies that mmap() should fail if length is 0" */ 229 if(len <= 0) { 230 return EINVAL; 231 } 232 233 if(m->m_mmap.fd == -1 || (m->m_mmap.flags & MAP_ANON)) { 234 /* actual memory in some form */ 235 mem_type_t *mt = NULL; 236 237 if(m->m_mmap.fd != -1) { 238 printf("VM: mmap: fd %d, len 0x%zx\n", m->m_mmap.fd, len); 239 return EINVAL; 240 } 241 242 /* Contiguous phys memory has to be preallocated. */ 243 if((m->m_mmap.flags & (MAP_CONTIG|MAP_PREALLOC)) == MAP_CONTIG) { 244 return EINVAL; 245 } 246 247 if(m->m_mmap.flags & MAP_CONTIG) { 248 mt = &mem_type_anon_contig; 249 } else mt = &mem_type_anon; 250 251 if(!(vr = mmap_region(vmp, addr, m->m_mmap.flags, len, 252 VR_WRITABLE | VR_ANON, mt, execpriv))) { 253 return ENOMEM; 254 } 255 } else { 256 /* File mapping might be disabled */ 257 if(!enable_filemap) return ENXIO; 258 259 /* For files, we only can't accept writable MAP_SHARED 260 * mappings. 261 */ 262 if((m->m_mmap.flags & MAP_SHARED) && (m->m_mmap.prot & PROT_WRITE)) { 263 return ENXIO; 264 } 265 266 if(vfs_request(VMVFSREQ_FDLOOKUP, m->m_mmap.fd, vmp, 0, 0, 267 mmap_file_cont, NULL, m, sizeof(*m)) != OK) { 268 printf("VM: vfs_request for mmap failed\n"); 269 return ENXIO; 270 } 271 272 /* request queued; don't reply. */ 273 return SUSPEND; 274 } 275 276 /* Return mapping, as seen from process. */ 277 m->m_mmap.retaddr = (void *) vr->vaddr; 278 279 return OK; 280 } 281 282 /*===========================================================================* 283 * map_perm_check * 284 *===========================================================================*/ 285 static int map_perm_check(endpoint_t caller, endpoint_t target, 286 phys_bytes physaddr, phys_bytes len) 287 { 288 int r; 289 290 /* TTY and memory are allowed to do anything. 291 * They have to be special cases as they have to be able to do 292 * anything; TTY even on behalf of anyone for the TIOCMAPMEM 293 * ioctl. MEM just for itself. 294 */ 295 if(caller == TTY_PROC_NR) 296 return OK; 297 if(caller == MEM_PROC_NR) 298 return OK; 299 300 /* Anyone else needs explicit permission from the kernel (ultimately 301 * set by PCI). 302 */ 303 r = sys_privquery_mem(target, physaddr, len); 304 305 return r; 306 } 307 308 /*===========================================================================* 309 * do_map_phys * 310 *===========================================================================*/ 311 int do_map_phys(message *m) 312 { 313 int r, n; 314 struct vmproc *vmp; 315 endpoint_t target; 316 struct vir_region *vr; 317 vir_bytes len; 318 phys_bytes startaddr; 319 size_t offset; 320 321 target = m->m_lsys_vm_map_phys.ep; 322 len = m->m_lsys_vm_map_phys.len; 323 324 if (len <= 0) return EINVAL; 325 326 if(target == SELF) 327 target = m->m_source; 328 329 if((r=vm_isokendpt(target, &n)) != OK) 330 return EINVAL; 331 332 startaddr = (vir_bytes)m->m_lsys_vm_map_phys.phaddr; 333 334 /* First check permission, then round range down/up. Caller can't 335 * help it if we can't map in lower than page granularity. 336 */ 337 if(map_perm_check(m->m_source, target, startaddr, len) != OK) { 338 printf("VM: unauthorized mapping of 0x%lx by %d for %d\n", 339 startaddr, m->m_source, target); 340 return EPERM; 341 } 342 343 vmp = &vmproc[n]; 344 345 offset = startaddr % VM_PAGE_SIZE; 346 len += offset; 347 startaddr -= offset; 348 349 if(len % VM_PAGE_SIZE) 350 len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); 351 352 if(!(vr = map_page_region(vmp, VM_MMAPBASE, VM_MMAPTOP, len, 353 VR_DIRECT | VR_WRITABLE, 0, &mem_type_directphys))) { 354 return ENOMEM; 355 } 356 357 phys_setphys(vr, startaddr); 358 359 m->m_lsys_vm_map_phys.reply = (void *) (vr->vaddr + offset); 360 361 return OK; 362 } 363 364 /*===========================================================================* 365 * do_remap * 366 *===========================================================================*/ 367 int do_remap(message *m) 368 { 369 int dn, sn; 370 vir_bytes da, sa; 371 size_t size; 372 u32_t flags; 373 struct vir_region *src_region, *vr; 374 struct vmproc *dvmp, *svmp; 375 int r; 376 int readonly; 377 378 if(m->m_type == VM_REMAP) 379 readonly = 0; 380 else if(m->m_type == VM_REMAP_RO) 381 readonly = 1; 382 else panic("do_remap: can't be"); 383 384 da = (vir_bytes) m->m_lsys_vm_vmremap.dest_addr; 385 sa = (vir_bytes) m->m_lsys_vm_vmremap.src_addr; 386 size = m->m_lsys_vm_vmremap.size; 387 388 if (size <= 0) return EINVAL; 389 390 if ((r = vm_isokendpt((endpoint_t) m->m_lsys_vm_vmremap.destination, &dn)) != OK) 391 return EINVAL; 392 if ((r = vm_isokendpt((endpoint_t) m->m_lsys_vm_vmremap.source, &sn)) != OK) 393 return EINVAL; 394 395 dvmp = &vmproc[dn]; 396 svmp = &vmproc[sn]; 397 398 if (!(src_region = map_lookup(svmp, sa, NULL))) 399 return EINVAL; 400 401 if(src_region->vaddr != sa) { 402 printf("VM: do_remap: not start of region.\n"); 403 return EFAULT; 404 } 405 406 if (size % VM_PAGE_SIZE) 407 size += VM_PAGE_SIZE - size % VM_PAGE_SIZE; 408 409 if(size != src_region->length) { 410 printf("VM: do_remap: not size of region.\n"); 411 return EFAULT; 412 } 413 414 flags = VR_SHARED; 415 if(!readonly) 416 flags |= VR_WRITABLE; 417 418 if(da) 419 vr = map_page_region(dvmp, da, 0, size, flags, 0, 420 &mem_type_shared); 421 else 422 vr = map_page_region(dvmp, VM_MMAPBASE, VM_MMAPTOP, size, 423 flags, 0, &mem_type_shared); 424 425 if(!vr) { 426 printf("VM: re-map of shared area failed\n"); 427 return ENOMEM; 428 } 429 430 shared_setsource(vr, svmp->vm_endpoint, src_region); 431 432 m->m_lsys_vm_vmremap.ret_addr = (void *) vr->vaddr; 433 return OK; 434 } 435 436 /*===========================================================================* 437 * do_get_phys * 438 *===========================================================================*/ 439 int do_get_phys(message *m) 440 { 441 int r, n; 442 struct vmproc *vmp; 443 endpoint_t target; 444 phys_bytes ret; 445 vir_bytes addr; 446 447 target = m->m_lc_vm_getphys.endpt; 448 addr = (vir_bytes) m->m_lc_vm_getphys.addr; 449 450 if ((r = vm_isokendpt(target, &n)) != OK) 451 return EINVAL; 452 453 vmp = &vmproc[n]; 454 455 r = map_get_phys(vmp, addr, &ret); 456 457 m->m_lc_vm_getphys.ret_addr = (void *) ret; 458 return r; 459 } 460 461 /*===========================================================================* 462 * do_get_refcount * 463 *===========================================================================*/ 464 int do_get_refcount(message *m) 465 { 466 int r, n; 467 struct vmproc *vmp; 468 endpoint_t target; 469 u8_t cnt; 470 vir_bytes addr; 471 472 target = m->m_lsys_vm_getref.endpt; 473 addr = (vir_bytes) m->m_lsys_vm_getref.addr; 474 475 if ((r = vm_isokendpt(target, &n)) != OK) 476 return EINVAL; 477 478 vmp = &vmproc[n]; 479 480 r = map_get_ref(vmp, addr, &cnt); 481 482 m->m_lsys_vm_getref.retc = cnt; 483 return r; 484 } 485 486 /*===========================================================================* 487 * munmap_vm_lin * 488 *===========================================================================*/ 489 int munmap_vm_lin(vir_bytes addr, size_t len) 490 { 491 if(addr % VM_PAGE_SIZE) { 492 printf("munmap_vm_lin: offset not page aligned\n"); 493 return EFAULT; 494 } 495 496 if(len % VM_PAGE_SIZE) { 497 printf("munmap_vm_lin: len not page aligned\n"); 498 return EFAULT; 499 } 500 501 if(pt_writemap(NULL, &vmproc[VM_PROC_NR].vm_pt, addr, MAP_NONE, len, 0, 502 WMF_OVERWRITE | WMF_FREE) != OK) { 503 printf("munmap_vm_lin: pt_writemap failed\n"); 504 return EFAULT; 505 } 506 507 return OK; 508 } 509 510 /*===========================================================================* 511 * do_munmap * 512 *===========================================================================*/ 513 int do_munmap(message *m) 514 { 515 int r, n; 516 struct vmproc *vmp; 517 struct vir_region *vr; 518 vir_bytes addr, len; 519 endpoint_t target = SELF; 520 521 if(m->m_type == VM_UNMAP_PHYS) { 522 target = m->m_lsys_vm_unmap_phys.ep; 523 } else if(m->m_type == VM_SHM_UNMAP) { 524 target = m->m_lc_vm_shm_unmap.forwhom; 525 } 526 527 if(target == SELF) 528 target = m->m_source; 529 530 if((r=vm_isokendpt(target, &n)) != OK) { 531 panic("do_mmap: message from strange source: %d", m->m_source); 532 } 533 534 vmp = &vmproc[n]; 535 536 if(m->m_source == VM_PROC_NR) { 537 /* VM munmap is a special case, the region we want to 538 * munmap may or may not be there in our data structures, 539 * depending on whether this is an updated VM instance or not. 540 */ 541 if(!region_search_root(&vmp->vm_regions_avl)) { 542 munmap_vm_lin(addr, m->VMUM_LEN); 543 } 544 else if((vr = map_lookup(vmp, addr, NULL))) { 545 if(map_unmap_region(vmp, vr, 0, m->VMUM_LEN) != OK) { 546 printf("VM: self map_unmap_region failed\n"); 547 } 548 } 549 return SUSPEND; 550 } 551 552 if(m->m_type == VM_UNMAP_PHYS) { 553 addr = (vir_bytes) m->m_lsys_vm_unmap_phys.vaddr; 554 } else if(m->m_type == VM_SHM_UNMAP) { 555 addr = (vir_bytes) m->m_lc_vm_shm_unmap.addr; 556 } else addr = (vir_bytes) m->VMUM_ADDR; 557 558 if(addr % VM_PAGE_SIZE) 559 return EFAULT; 560 561 if(m->m_type == VM_UNMAP_PHYS || m->m_type == VM_SHM_UNMAP) { 562 struct vir_region *vr; 563 if(!(vr = map_lookup(vmp, addr, NULL))) { 564 printf("VM: unmap: address 0x%lx not found in %d\n", 565 addr, target); 566 sys_diagctl_stacktrace(target); 567 return EFAULT; 568 } 569 len = vr->length; 570 } else len = roundup(m->VMUM_LEN, VM_PAGE_SIZE); 571 572 return map_unmap_range(vmp, addr, len); 573 } 574 575