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