SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

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 ]