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 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 ]