|
[ source navigation ] [ diff markup ] [ identifier search ] [ general search ] |
|||
|
001 /* Copyright (C) 2005 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 /** 212 * The definition of a mapped resource. Typically, a mapped resource 213 * is a file or a device: in both cases, only part of the resource is 214 * mapped by each VR, this part is given by the offset_in_resource 215 * field of the VR, and the size field of the VR. 216 */ 217 struct sos_umem_vmm_mapped_resource 218 { 219 /** Represent the maximum authrized SOS_VR_PROT_* for the VRs mapping 220 it */ 221 sos_ui32_t allowed_access_rights; 222 223 /** Some flags associated with the resource. Currently only 224 SOS_MAPPED_RESOURCE_ANONYMOUS is supported */ 225 sos_ui32_t flags; 226 227 /** List of VRs mapping this resource */ 228 struct sos_umem_vmm_vr * list_vr; 229 230 /** 231 * MANDATORY Callback function called when a new VR is created, 232 * which maps the resource. This callback is allowed to change the 233 * following fields of the VR: 234 * - sos_umem_vmm_set_ops_of_vr() 235 */ 236 sos_ret_t (*mmap)(struct sos_umem_vmm_vr *); 237 238 /** 239 * Custom data that the user is free to define: the umem_vmm 240 * subsystem won't ever look at it or change it 241 */ 242 void *custom_data; 243 }; 244 245 246 /** Inidicate that this resource is not backed by any physical 247 storage. This means that the "offset_in_resource" field of the 248 VRs will be computed by sos_umem_vmm_map() */ 249 #define SOS_MAPPED_RESOURCE_ANONYMOUS (1 << 0) 250 251 252 /** 253 * Physical address of THE page (full of 0s) used for anonymous 254 * mappings. Anybody can map it provided it is ALWAYS in read-only 255 * mode 256 */ 257 extern sos_paddr_t sos_zero_physpage; 258 259 /** 260 * "ZERO" page address mapped in kernel space 261 */ 262 extern sos_vaddr_t sos_zero_kernelpage; 263 264 265 /** 266 * Setup the umem_vmm subsystem. 267 */ 268 sos_ret_t sos_umem_vmm_subsystem_setup(); 269 270 271 /** 272 * Create a new, empty, address space 273 * 274 * @param owner The process that will own the new address space 275 * 276 * @note no need to call 277 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 278 */ 279 struct sos_umem_vmm_as * 280 sos_umem_vmm_create_empty_as(struct sos_process *owner); 281 282 283 /** 284 * Create a new address space, copy of the current thread's address 285 * space. All the translations belonging to private mappings are 286 * marked 'read-only' to activate the "copy-on-write" semantics. 287 * 288 * @param owner The process that will hold the new address space 289 * 290 * @note automatically calls 291 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 292 */ 293 struct sos_umem_vmm_as * 294 sos_umem_vmm_duplicate_current_thread_as(struct sos_process *owner); 295 296 297 /** 298 * Called at process deletion time, to remove all mappings present in 299 * the address space. This function not only delete all the VR data 300 * structures, it also calls the unmap()/unref() callbacks of these 301 * VRs. However, the physical pages mapped inside the address space 302 * won't be unmapped at this stage: they will be unmapped all in one 303 * go when the undelying mm_context will become unused. 304 * 305 * @note no need to call 306 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 307 */ 308 sos_ret_t 309 sos_umem_vmm_delete_as(struct sos_umem_vmm_as * as); 310 311 312 /* 313 * Accessor functions for the address space 314 */ 315 316 /** Retrieve the pointer (NOT a new reference !) to the process owning 317 the given address space. */ 318 struct sos_process * 319 sos_umem_vmm_get_process(struct sos_umem_vmm_as * as); 320 321 /** Retrieve the pointer (NOT a new reference !) to the MMU 322 configuration for the given address space */ 323 struct sos_mm_context * 324 sos_umem_vmm_get_mm_context(struct sos_umem_vmm_as * as); 325 326 /** Retrieve a pointer to the VR that covers the given virtual address 327 in the given address space */ 328 struct sos_umem_vmm_vr * 329 sos_umem_vmm_get_vr_at_address(struct sos_umem_vmm_as * as, 330 sos_uaddr_t uaddr); 331 332 333 /* 334 * Accessor functions for the virtual regions 335 */ 336 337 /** Retrieve the address space owning the given VR */ 338 struct sos_umem_vmm_as * 339 sos_umem_vmm_get_as_of_vr(struct sos_umem_vmm_vr * vr); 340 341 /** Retrieve the set of callbacks of the given VR */ 342 struct sos_umem_vmm_vr_ops * 343 sos_umem_vmm_get_ops_of_vr(struct sos_umem_vmm_vr * vr); 344 345 /** Retrieve the current protection of the given VR */ 346 sos_ui32_t sos_umem_vmm_get_prot_of_vr(struct sos_umem_vmm_vr * vr); 347 348 /** Retrieve the flags of the given VR. One will especially be 349 interested in the SOS_VR_MAP_SHARED bit */ 350 sos_ui32_t sos_umem_vmm_get_flags_of_vr(struct sos_umem_vmm_vr * vr); 351 352 /** Retrieve the resource mapped by the VR */ 353 struct sos_umem_vmm_mapped_resource * 354 sos_umem_vmm_get_mapped_resource_of_vr(struct sos_umem_vmm_vr * vr); 355 356 /** Retrieve the start user address for the given mapping */ 357 sos_uaddr_t sos_umem_vmm_get_start_of_vr(struct sos_umem_vmm_vr * vr); 358 359 /** Retrieve the size (in user space) of the given mapping */ 360 sos_size_t sos_umem_vmm_get_size_of_vr(struct sos_umem_vmm_vr * vr); 361 362 /** Retrieve the offset in the resource of the mapping */ 363 sos_luoffset_t 364 sos_umem_vmm_get_offset_in_resource(struct sos_umem_vmm_vr * vr); 365 366 367 /* 368 * Restricted accessor functions. May only be called from inside the 369 * map() callback of a VR 370 */ 371 372 /** 373 * Function that is not called directly by the umem_subsystem: It MUST 374 * always be called by the mmap() callback of the resource being 375 * mapped (@see sos_umem_vmm_mapped_resource::mmap()). The mmap() 376 * method is called at VR creation time, automatically by 377 * sos_umem_vmm_map(). 378 * 379 * @note The VR MUST NOT already have a set of operations (fatal error) 380 */ 381 sos_ret_t sos_umem_vmm_set_ops_of_vr(struct sos_umem_vmm_vr * vr, 382 struct sos_umem_vmm_vr_ops * ops); 383 384 385 /* 386 * mmap API 387 */ 388 389 390 /** sos_umem_vmm_map() flag: the address given as parameter to 391 sos_umem_vmm_map() is not only a hint, it is where the VR is 392 expected to be mapped */ 393 #define SOS_VR_MAP_FIXED (1 << 31) 394 395 396 /** 397 * Add a new VR in the given address space, that maps the given 398 * resource. Its semantics follows that of the UNIX mmap() call 399 * (including SOS_VR_MAP_FIXED). Real mapping in physical memory will 400 * be delayed as much as possible (demand paging) and the physical 401 * pages will be shared among processes as much as possible (COW). 402 * 403 * @param *uaddr must be page-aligned, and can be NULL. It stores the 404 * address of the mapping, when successful 405 * 406 * @param size The size of the mapping in user space 407 * 408 * @param access_rights The allowed accesses to the mapped resource 409 * (@see SOS_VM_MAP_PROT_* flags in hwcore/paging.h) 410 * 411 * @param flags mainly: is it shared mapping (SOS_VR_MAP_SHARED) or not ? 412 * 413 * @param resource MUST be NON NULL, and its mmap() method must also 414 * be NON NULL 415 * 416 * @param offset_in_resource where inside the resource does the 417 * mapping start 418 * 419 * @return SOS_OK on success (address of the mapping stored in uaddr) 420 * 421 * @note no need to call 422 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 423 */ 424 sos_ret_t 425 sos_umem_vmm_map(struct sos_umem_vmm_as * as, 426 sos_uaddr_t *uaddr, sos_size_t size, 427 sos_ui32_t access_rights, 428 sos_ui32_t flags, 429 struct sos_umem_vmm_mapped_resource * resource, 430 sos_luoffset_t offset_in_resource); 431 432 433 /** 434 * Unmap the given address interval. This might imply the partial or 435 * complete unmapping of 0, 1 or more VRs. Same semantics as unix 436 * munmap() 437 * 438 * @note automatically calls 439 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 440 */ 441 sos_ret_t 442 sos_umem_vmm_unmap(struct sos_umem_vmm_as * as, 443 sos_uaddr_t uaddr, sos_size_t size); 444 445 446 /** 447 * Change the access rights of the given address interval. This might 448 * concern 0, 1 or more VRs, and result in the splitting in 1 or 2 VRs 449 * if they are partially concerned by the change in protection.. Same 450 * semantics as unix mprotect() 451 * 452 * @param new_access_rights @see SOS_VM_MAP_PROT_* flags in hwcore/paging.h 453 * 454 * @note MAKE SURE YOU CALL 455 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 456 */ 457 sos_ret_t 458 sos_umem_vmm_chprot(struct sos_umem_vmm_as * as, 459 sos_uaddr_t uaddr, sos_size_t size, 460 sos_ui32_t new_access_rights); 461 462 463 464 /** 465 * Flag for sos_umem_vmm_resize() to indicate that the VR being 466 * resized can be moved elsewhere if there is not enough room to 467 * resize it in-place 468 */ 469 #define SOS_VR_REMAP_MAYMOVE (1 << 30) 470 471 /** 472 * Lookup the region covering the old_uaddr/old_size interval, and 473 * resize it to match the *new_uaddr/new_size requirements. This is a 474 * variant of Unix's mremap() that allow to resize the VR by its 475 * low-addresses (mremap only allows to resize a VR by its 476 * top-address). 477 * 478 * @param old_uaddr Low address of the interval covered by the VR to resize 479 * 480 * @param old_size Size of the interval covered by the VR to resize 481 * 482 * @param new_uaddr MUST BE page-aligned ! Initially: the new start 483 * address of the VR, allowing to change the low-address. Once the 484 * function returns: the actual start address of the VR (which might 485 * be different, due to SOS_VR_REMAP_MAYMOVE flag, when set) 486 * 487 * @param new_size The size requested for the VR. Might be 488 * smaller/larger than the original VR size 489 * 490 * @param flags Essentially: 0 or SOS_VR_REMAP_MAYMOVE 491 * 492 * @note MAKE SURE YOU CALL 493 * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() 494 */ 495 sos_ret_t 496 sos_umem_vmm_resize(struct sos_umem_vmm_as * as, 497 sos_uaddr_t old_uaddr, sos_size_t old_size, 498 sos_uaddr_t /* in/out */*new_uaddr, sos_size_t new_size, 499 sos_ui32_t flags); 500 501 502 /* 503 * Heap management API (ie libc's malloc support) 504 */ 505 506 /** 507 * Change the top address of the heap. 508 * 509 * @param new_top_uaddr When NULL don't change anything. Otherwise: 510 * change the top address of the heap 511 * 512 * @return The top address of the heap after having been updated (if 513 * ever) 514 */ 515 sos_uaddr_t 516 sos_umem_vmm_brk(struct sos_umem_vmm_as * as, 517 sos_uaddr_t new_top_uaddr); 518 519 520 /* 521 * Reserved functions 522 */ 523 524 /** 525 * Called by the main page fault handler when a physical page is not 526 * mapped for the given address of the current address space. This 527 * function is called only if: 528 * - The access (read / write) is allowed on this VR 529 * - no physical page is mapped yet 530 * This function first calls the sos_paging_try_resolve_COW() to 531 * resolve the COW if a COW access pattern is detected, and, if 532 * unsuccessful, the sos_umem_vmm_vr_ops::page_in() method of the VR. 533 * 534 * @param uaddr The address that was accessed, causing the fault. 535 * 536 * @param write_access Was it write access ? 537 * 538 * @param user_access Was it a user access ? Or a kernel access (by 539 * uaccess.h functions) ? 540 * 541 * @return SOS_OK when the fault could be solved, ie a page could be 542 * mapped for the given address. -SOS_EFAULT otherwise, meaning the 543 * faulting thread should be terminated or signalled (SIGSEGV) 544 * 545 * @note: The current mm_context MUST be that of the current thread 546 * (which caused the exception) ! 547 */ 548 sos_ret_t sos_umem_vmm_try_resolve_page_fault(sos_uaddr_t uaddr, 549 sos_bool_t write_access, 550 sos_bool_t user_access); 551 552 553 554 /** 555 * Initialize the initial heap once the program code/data is mapped 556 * Called by the ELF32 program loader. 557 */ 558 sos_ret_t 559 sos_umem_vmm_init_heap(struct sos_umem_vmm_as * as, 560 sos_uaddr_t heap_start); 561 562 #endif /* _SOS_UMEM_VMM_H_ */
[ source navigation ] | [ diff markup ] | [ identifier search ] | [ general search ] |