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