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