|
[ source navigation ] [ diff markup ] [ identifier search ] [ general search ] |
|||
|
001 /* Copyright (C) 2005,2006 David Decotigny 002 003 This program is free software; you can redistribute it and/or 004 modify it under the terms of the GNU General Public License 005 as published by the Free Software Foundation; either version 2 006 of the License, or (at your option) any later version. 007 008 This program is distributed in the hope that it will be useful, 009 but WITHOUT ANY WARRANTY; without even the implied warranty of 010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 011 GNU General Public License for more details. 012 013 You should have received a copy of the GNU General Public License 014 along with this program; if not, write to the Free Software 015 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 016 USA. 017 */ 018 #ifndef _SOS_UMEM_VMM_H_ 019 #define _SOS_UMEM_VMM_H_ 020 021 /** 022 * @file umem_vmm.h 023 * 024 * Management of the address space of a process in SOS. The so-called 025 * "address space" of a process consists in the description of the 026 * virtual addresses that are valid in the user space of a process (in 027 * SOS: addresses 1G-4G). The kernel-space of a process is managed by 028 * the "kmem" subsystem, and is kept identical accross all the 029 * processes in the system. 030 * 031 * The umem_vmm subsystem handles the following features: 032 * - demand-mapping of resourcs (files: mmap): mapping in physical RAM 033 * will be delayed as much as possible, until the process really 034 * need to access the mapped addresses 035 * - mprotect/mremap support 036 * - private and shared mappings 037 * - Copy-On-Write (COW) of the private mappings upon fork() to favour 038 * shared physical memory as much as possible 039 * - "heap" management (brk/sbrk) 040 * 041 * Swap is NOT supported (yet), which means that the following is NOT 042 * supported: 043 * - locked/reserved I/O pages (everything is locked in RAM) 044 * - "safe" demand-mapping of anonymous pages, ie conservative VMM 045 * allocation (alloc of anonymous pages on the swap) 046 * Other unsupported features: 047 * - dynamically-resizable regions (Linux's GROWUP/GROWDOWN vma): the 048 * user stack is expected to have a suitable virtual size from the 049 * beginning, or sos_umem_vmm_resize() must be used explicitely to 050 * resize it 051 * - no provision of "stack size" accounting, since there are 052 * multiple stacks (ie user threads) in a process: which stack to 053 * consider ??? 054 * 055 * The address space is divided into "virtual regions" (aka "VR") that 056 * describe a single mapping, aka a segment of contiguous pages in 057 * user-space virtual memory. Each such virtual region "maps" a 058 * "resource" and is characterised by: 059 * - its base address and length in user-space 060 * - the allowed accesses, aka "protection" (read-only or read/write) 061 * - the resource it maps in virtual memory 062 * 063 * A so-called resource is typically: 064 * - a file 065 * - a device 066 * - an area initially full of zeros (the VR mapping this are called 067 * "anonymous mappings") 068 * 069 * The implementation is very close to that of Linux and Kos. This is 070 * a "simple" implementation, not the most elegant one, such as those 071 * based on "shadow objects" hierarchies as found in BSD 4.4 and Mach, 072 * or that of Solaris (based on the "anon" lists). Actually, this 073 * implementation does not use "shadow-objects"/anon list when a COW 074 * page of a shared mapping is made anonymous. This won't hurt the 075 * implementation of the basic demand-mapping mechanism; on the 076 * contrary, it will make things simpler. But this will largely impact 077 * the implementation of the swap-in/swap-out strategies, as these 078 * would require a non trivial intrication of low-level and higher 079 * level algorithms. 080 */ 081 082 083 /** 084 * Definition of an "address space" in Kos. This is an opaque 085 * structure defined in umem_vmm.c. Its main role is to list virtual 086 * regions. It mainly consists in: 087 * - a reference to the process owning it 088 * - maximum allowed protection (ie can it be mapped read-only or 089 * read/write ?) 090 * - the list of VRs mapping resources 091 * - a mm_context that reflects the configuration of the MMU 092 * - the location of the heap for this process 093 * - statistics 094 */ 095 struct sos_umem_vmm_as; 096 097 098 /** 099 * Definition of a "virtual region". Linux would call them "vma" 100 * (Virtual Memory Area), and Solaris: "segments". It mainly consists 101 * in: 102 * - the start/end addresses of the mapping 103 * - a pointer to the resource that it maps 104 * - the type of mapping (shared/private) 105 * - the actual protection flags (@see SOS_VM_MAP_PROT_* flags in 106 * hwcore/paging.h) 107 * - a set of callbacks (@see sos_umem_vmm_vr_ops below) automatically 108 * called by the umem_vmm subsystem each time the VR is modified 109 */ 110 struct sos_umem_vmm_vr; 111 112 113 /** VR flag: region can be shared between a process and its 114 children */ 115 #define SOS_VR_MAP_SHARED (1 << 0) 116 117 118 #include <sos/types.h> 119 #include <sos/process.h> 120 121 122 /** 123 * The callbacks applicable on a virtual region. Automatically called 124 * by the umem_vmm subsystem. 125 * 126 * Calling sequences: 127 * - duplicate_as() (aka fork()): 128 * vr->ops->ref() 129 * add vr to lists 130 * - delete_as() (aka exit()): 131 * vr->ops->unmap() 132 * remove vr from lists 133 * vr->ops->unref() 134 * - mmap(): 135 * -> left + new + right VRs can fusion: 136 * remove right_vr from list 137 * right_vr->ops->unref() 138 * -> left + new VRs can fusion: 139 * nothing 140 * -> new + right VRs can fusion: 141 * nothing 142 * -> isolated: 143 * add new_vr to lists 144 * new_vr->map() 145 * new_vr->ops->ref() 146 * - munmap(): 147 * -> VR totally unmapped: 148 * vr->ops->unmap() 149 * remove vr from lists 150 * vr->ops->unref() 151 * -> VR unmapped in the middle (split into 2): 152 * add (new) right VR into the lists 153 * vr->unmap(middle_unmapped_area) 154 * right_vr->ops->ref() 155 * -> VR unmapped on its left: 156 * vr->ops->unmap(left_unmapped_area) 157 * -> VR unmapped on its right: 158 * vr->ops->unmap(right_unmapped_area) 159 * - chprot(): 160 * -> VR totally chprot: 161 * nothing 162 * -> VR chprot in the middle (split into 3): 163 * add (new) middle+right VRs into the lists 164 * middle_vr->ops->ref() 165 * right_vr->ops->ref() 166 * -> VR chprot on its left (split into 2): 167 * add (new) right VR into the lists 168 * right_vr->ops->ref() 169 * -> VR chprot on its right (split into 2): 170 * add (new) right VR into the lists 171 * right_vr->ops->ref() 172 * - resize(): 173 * -> if moving the VR: map/unmap 174 * -> otherwise: nothing 175 */ 176 struct sos_umem_vmm_vr_ops 177 { 178 /** 179 * Called after the virtual region has been inserted 180 * inside its address space. 181 * @note Optional 182 */ 183 void (*ref)(struct sos_umem_vmm_vr * vr); 184 185 /** 186 * Called when the virtual region is removed from its 187 * address space 188 * @note Optional 189 */ 190 void (*unref)(struct sos_umem_vmm_vr * vr); 191 192 /** 193 * Called when part or all a VR is unmapped 194 * @note Optional 195 */ 196 void (*unmap)(struct sos_umem_vmm_vr * vr, 197 sos_uaddr_t uaddr, sos_size_t size); 198 199 /** 200 * Called by the page fault handler to map data at the given virtual 201 * address. In the Linux kernel, this callback is named "nopage". 202 * 203 * @note MANDATORY 204 */ 205 sos_ret_t (*page_in)(struct sos_umem_vmm_vr * vr, 206 sos_uaddr_t uaddr, 207 sos_bool_t write_access); 208 209 210 /** 211 * Called to synchronize the contents of the given page with its 212 * backing store. This method is responsible for resetting the dirty 213 * flag of the page (@see sos_paging_set_dirty). Appropriate locking 214 * MUST be handled internally by this method. 215 * 216 * @note Optional 217 */ 218 sos_ret_t (*sync_page)(struct sos_umem_vmm_vr * vr, 219 sos_uaddr_t page_uaddr, 220 sos_ui32_t flags); 221 /** Flags for msync */ 222 #define SOS_MSYNC_SYNC (1 << 0) 223 #define SOS_MSYNC_ASYNC (0 << 0) 224 }; 225 226 227 /** 228 * The definition of a mapped resource. Typically, a mapped resource 229 * is a file or a device: in both cases, only part of the resource is 230 * mapped by each VR, this part is given by the offset_in_resource 231 * field of the VR, and the size field of the VR. 232 */ 233 struct sos_umem_vmm_mapped_resource 234 { 235 /** Represent the maximum authrized SOS_VR_PROT_* for the VRs mapping 236 it */ 237 sos_ui32_t allowed_access_rights; 238 239 /** Some flags associated with the resource. Currently only 240 SOS_MAPPED_RESOURCE_ANONYMOUS is supported */ 241 sos_ui32_t flags; 242 243 /** List of VRs mapping this resource */ 244 struct sos_umem_vmm_vr * list_vr; 245 246 /** 247 * MANDATORY Callback function called when a new VR is created, 248 * which maps the resource. This callback is allowed to change the 249 * following fields of the VR: 250 * - sos_umem_vmm_set_ops_of_vr() 251 */ 252 sos_ret_t (*mmap)(struct sos_umem_vmm_vr *); 253 254 /** 255 * Custom data that the user is free to define: the umem_vmm 256 * subsystem won't ever look at it or change it. 257 */ 258 void *custom_data; 259 }; 260 261 262 /** Inidicate that this resource is not backed by any physical 263 storage. This means that the "offset_in_resource" field of the 264 VRs will be computed by sos_umem_vmm_map() */ 265 #define SOS_MAPPED_RESOURCE_ANONYMOUS (1 << 0) 266 267 268 /** 269 * Physical address of THE page (full of 0s) used for anonymous 270 * mappings. Anybody can map it provided it is ALWAYS in read-only 271 * mode 272 */ 273 extern sos_paddr_t sos_zero_physpage; 274 275 /** 276 * "ZERO" page address mapped in kernel space 277 */ 278 extern sos_vaddr_t sos_zero_kernelpage; 279 280 281 /** 282 * Setup the umem_vmm subsystem. 283 */ 284 sos_ret_t sos_umem_vmm_subsystem_setup(void); 285 286 287 /** 288 * Create a new, empty, address space 289 * 290 * @param owner The process that will own the new address space 291 * 292 * @note no need to call 293 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 294 */ 295 struct sos_umem_vmm_as * 296 sos_umem_vmm_create_empty_as(struct sos_process *owner); 297 298 299 /** 300 * Create a new address space, copy of the current thread's address 301 * space. All the translations belonging to private mappings are 302 * marked 'read-only' to activate the "copy-on-write" semantics. 303 * 304 * @param owner The process that will hold the new address space 305 * 306 * @note automatically calls 307 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 308 */ 309 struct sos_umem_vmm_as * 310 sos_umem_vmm_duplicate_current_thread_as(struct sos_process *owner); 311 312 313 /** 314 * Called at process deletion time, to remove all mappings present in 315 * the address space. This function not only delete all the VR data 316 * structures, it also calls the unmap()/unref() callbacks of these 317 * VRs. However, the physical pages mapped inside the address space 318 * won't be unmapped at this stage: they will be unmapped all in one 319 * go when the undelying mm_context will become unused. 320 * 321 * @note no need to call 322 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 323 */ 324 sos_ret_t 325 sos_umem_vmm_delete_as(struct sos_umem_vmm_as * as); 326 327 328 /* 329 * Accessor functions for the address space 330 */ 331 332 /** Retrieve the pointer (NOT a new reference !) to the process owning 333 the given address space. */ 334 struct sos_process * 335 sos_umem_vmm_get_process(struct sos_umem_vmm_as * as); 336 337 /** Retrieve the pointer (NOT a new reference !) to the MMU 338 configuration for the given address space */ 339 struct sos_mm_context * 340 sos_umem_vmm_get_mm_context(struct sos_umem_vmm_as * as); 341 342 /** Retrieve a pointer to the VR that covers the given virtual address 343 in the given address space */ 344 struct sos_umem_vmm_vr * 345 sos_umem_vmm_get_vr_at_address(struct sos_umem_vmm_as * as, 346 sos_uaddr_t uaddr); 347 348 349 /* 350 * Accessor functions for the virtual regions 351 */ 352 353 /** Retrieve the address space owning the given VR */ 354 struct sos_umem_vmm_as * 355 sos_umem_vmm_get_as_of_vr(struct sos_umem_vmm_vr * vr); 356 357 /** Retrieve the set of callbacks of the given VR */ 358 struct sos_umem_vmm_vr_ops * 359 sos_umem_vmm_get_ops_of_vr(struct sos_umem_vmm_vr * vr); 360 361 /** Retrieve the current protection of the given VR */ 362 sos_ui32_t sos_umem_vmm_get_prot_of_vr(struct sos_umem_vmm_vr * vr); 363 364 /** Retrieve the flags of the given VR. One will especially be 365 interested in the SOS_VR_MAP_SHARED bit */ 366 sos_ui32_t sos_umem_vmm_get_flags_of_vr(struct sos_umem_vmm_vr * vr); 367 368 /** Retrieve the resource mapped by the VR */ 369 struct sos_umem_vmm_mapped_resource * 370 sos_umem_vmm_get_mapped_resource_of_vr(struct sos_umem_vmm_vr * vr); 371 372 /** Retrieve the start user address for the given mapping */ 373 sos_uaddr_t sos_umem_vmm_get_start_of_vr(struct sos_umem_vmm_vr * vr); 374 375 /** Retrieve the size (in user space) of the given mapping */ 376 sos_size_t sos_umem_vmm_get_size_of_vr(struct sos_umem_vmm_vr * vr); 377 378 /** Retrieve the offset in the resource of the mapping */ 379 sos_luoffset_t 380 sos_umem_vmm_get_offset_in_resource(struct sos_umem_vmm_vr * vr); 381 382 383 /* 384 * Restricted accessor functions. May only be called from inside the 385 * map() callback of a VR 386 */ 387 388 /** 389 * Function that is not called directly by the umem_subsystem: It MUST 390 * always be called by the mmap() callback of the resource being 391 * mapped (@see sos_umem_vmm_mapped_resource::mmap()). The mmap() 392 * method is called at VR creation time, automatically by 393 * sos_umem_vmm_map(). 394 * 395 * @note The VR MUST NOT already have a set of operations (fatal error) 396 */ 397 sos_ret_t sos_umem_vmm_set_ops_of_vr(struct sos_umem_vmm_vr * vr, 398 struct sos_umem_vmm_vr_ops * ops); 399 400 401 /* 402 * mmap API 403 */ 404 405 406 /** sos_umem_vmm_map() flag: the address given as parameter to 407 sos_umem_vmm_map() is not only a hint, it is where the VR is 408 expected to be mapped */ 409 #define SOS_VR_MAP_FIXED (1 << 31) 410 411 412 /** 413 * Add a new VR in the given address space, that maps the given 414 * resource. Its semantics follows that of the UNIX mmap() call 415 * (including SOS_VR_MAP_FIXED). Real mapping in physical memory will 416 * be delayed as much as possible (demand paging) and the physical 417 * pages will be shared among processes as much as possible (COW). 418 * 419 * @param *uaddr must be page-aligned, and can be NULL. It stores the 420 * address of the mapping, when successful 421 * 422 * @param size The size of the mapping in user space 423 * 424 * @param access_rights The allowed accesses to the mapped resource 425 * (@see SOS_VM_MAP_PROT_* flags in hwcore/paging.h) 426 * 427 * @param flags mainly: is it shared mapping (SOS_VR_MAP_SHARED) or not ? 428 * 429 * @param resource MUST be NON NULL, and its mmap() method must also 430 * be NON NULL 431 * 432 * @param offset_in_resource where inside the resource does the 433 * mapping start 434 * 435 * @return SOS_OK on success (address of the mapping stored in uaddr) 436 * 437 * @note no need to call 438 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 439 */ 440 sos_ret_t 441 sos_umem_vmm_map(struct sos_umem_vmm_as * as, 442 sos_uaddr_t *uaddr, sos_size_t size, 443 sos_ui32_t access_rights, 444 sos_ui32_t flags, 445 struct sos_umem_vmm_mapped_resource * resource, 446 sos_luoffset_t offset_in_resource); 447 448 449 /** 450 * Unmap the given address interval. This might imply the partial or 451 * complete unmapping of 0, 1 or more VRs. Same semantics as unix 452 * munmap() 453 * 454 * @note automatically calls 455 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 456 */ 457 sos_ret_t 458 sos_umem_vmm_unmap(struct sos_umem_vmm_as * as, 459 sos_uaddr_t uaddr, sos_size_t size); 460 461 462 /** 463 * Flush the given pages to backing store. Call the sync_page method 464 * for each of the dirty pages. The MMU is expected to be configured 465 * for the given AS ! 466 * 467 * @note MAKE SURE YOU CALL 468 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 469 */ 470 sos_ret_t 471 sos_umem_vmm_sync(struct sos_umem_vmm_as * as, 472 sos_uaddr_t uaddr, sos_size_t size, 473 sos_ui32_t flags); 474 475 476 /** 477 * Change the access rights of the given address interval. This might 478 * concern 0, 1 or more VRs, and result in the splitting in 1 or 2 VRs 479 * if they are partially concerned by the change in protection.. Same 480 * semantics as unix mprotect() 481 * 482 * @param new_access_rights @see SOS_VM_MAP_PROT_* flags in hwcore/paging.h 483 * 484 * @note MAKE SURE YOU CALL 485 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 486 */ 487 sos_ret_t 488 sos_umem_vmm_chprot(struct sos_umem_vmm_as * as, 489 sos_uaddr_t uaddr, sos_size_t size, 490 sos_ui32_t new_access_rights); 491 492 493 494 /** 495 * Flag for sos_umem_vmm_resize() to indicate that the VR being 496 * resized can be moved elsewhere if there is not enough room to 497 * resize it in-place 498 */ 499 #define SOS_VR_REMAP_MAYMOVE (1 << 30) 500 501 /** 502 * Lookup the region covering the old_uaddr/old_size interval, and 503 * resize it to match the *new_uaddr/new_size requirements. This is a 504 * variant of Unix's mremap() that allow to resize the VR by its 505 * low-addresses (mremap only allows to resize a VR by its 506 * top-address). 507 * 508 * @param old_uaddr Low address of the interval covered by the VR to resize 509 * 510 * @param old_size Size of the interval covered by the VR to resize 511 * 512 * @param new_uaddr MUST BE page-aligned ! Initially: the new start 513 * address of the VR, allowing to change the low-address. Once the 514 * function returns: the actual start address of the VR (which might 515 * be different, due to SOS_VR_REMAP_MAYMOVE flag, when set) 516 * 517 * @param new_size The size requested for the VR. Might be 518 * smaller/larger than the original VR size 519 * 520 * @param flags Essentially: 0 or SOS_VR_REMAP_MAYMOVE 521 * 522 * @note MAKE SURE YOU CALL 523 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 524 */ 525 sos_ret_t 526 sos_umem_vmm_resize(struct sos_umem_vmm_as * as, 527 sos_uaddr_t old_uaddr, sos_size_t old_size, 528 sos_uaddr_t /* in/out */*new_uaddr, sos_size_t new_size, 529 sos_ui32_t flags); 530 531 532 /* 533 * Heap management API (ie libc's malloc support) 534 */ 535 536 /** 537 * Change the top address of the heap. 538 * 539 * @param new_top_uaddr When NULL don't change anything. Otherwise: 540 * change the top address of the heap 541 * 542 * @return The top address of the heap after having been updated (if 543 * ever) 544 */ 545 sos_uaddr_t 546 sos_umem_vmm_brk(struct sos_umem_vmm_as * as, 547 sos_uaddr_t new_top_uaddr); 548 549 550 /* 551 * Reserved functions 552 */ 553 554 /** 555 * Called by the main page fault handler when a physical page is not 556 * mapped for the given address of the current address space. This 557 * function is called only if: 558 * - The access (read / write) is allowed on this VR 559 * - no physical page is mapped yet 560 * This function first calls the sos_paging_try_resolve_COW() to 561 * resolve the COW if a COW access pattern is detected, and, if 562 * unsuccessful, the sos_umem_vmm_vr_ops::page_in() method of the VR. 563 * 564 * @param uaddr The address that was accessed, causing the fault. 565 * 566 * @param write_access Was it write access ? 567 * 568 * @param user_access Was it a user access ? Or a kernel access (by 569 * uaccess.h functions) ? 570 * 571 * @return SOS_OK when the fault could be solved, ie a page could be 572 * mapped for the given address. -SOS_EFAULT otherwise, meaning the 573 * faulting thread should be terminated or signalled (SIGSEGV) 574 * 575 * @note: The current mm_context MUST be that of the current thread 576 * (which caused the exception) ! 577 */ 578 sos_ret_t sos_umem_vmm_try_resolve_page_fault(sos_uaddr_t uaddr, 579 sos_bool_t write_access, 580 sos_bool_t user_access); 581 582 583 584 /** 585 * Initialize the initial heap once the program code/data is mapped 586 * Called by the ELF32 program loader. 587 */ 588 sos_ret_t 589 sos_umem_vmm_init_heap(struct sos_umem_vmm_as * as, 590 sos_uaddr_t heap_start); 591 592 #endif /* _SOS_UMEM_VMM_H_ */
[ source navigation ] | [ diff markup ] | [ identifier search ] | [ general search ] |