[Kos-cvs] kos/modules/x86/mm Makefile, 1.4, 1.5 _mm.h, 1.10, 1.11 _rmap.c, 1.13, 1.14 _team_mm_context.c, 1.18, 1.19 _vmap.c, 1.26, 1.27 mm.c, 1.14, 1.15 mm.h, 1.14, 1.15

thomas at kos.enix.org thomas at kos.enix.org
Tue Dec 28 19:45:05 CET 2004


Update of /var/cvs/kos/kos/modules/x86/mm
In directory the-doors:/tmp/cvs-serv10813/modules/x86/mm

Modified Files:
	Makefile _mm.h _rmap.c _team_mm_context.c _vmap.c mm.c mm.h 
Log Message:
2004-12-28  Thomas Petazzoni  <thomas at crazy.kos.nx>

	* modules/x86/task/task.c: Try to restrict access to exported
	symbol.

	* modules/x86/task/_thread_cpu_context.c: Move to the new PMM
	system.

	* modules/x86/task/Makefile (all): arch_task.ro instead of
	arch-task.ro.

	* modules/x86/mm/_team_mm_context.c: More informations.

	* modules/x86/mm/_mm.h, modules/x86/mm/mm.c, modules/x86/mm/_rmap.c,
	modules/x86/mm/_vmap.c: The new VMAP/RMAP system. We also make
	sure access to all exported function is restricted to the VMM
	module. 

	* modules/x86/mm/Makefile (all): arch_mm.ro instead of
	arch-mm.ro. 

	* modules/x86/lib/Makefile (all): Rename to arch_lib.ro instead of
	arch-lib.ro. 

	* modules/x86/internals.h: More definitions on the address space
	configuration. 

	* modules/vmm/vmm.h (struct address_space): Add a mutex and a
	spinlock to protect address space.

	* modules/vmm/vmm.c: Restrict access to some exported
	functions. More work has to be done in this area.

	* modules/vmm/_vmm_map.c: Part of the new vmap system.

	* modules/vmm/_vmm_as.c: Make the appropriate lock/unlock on the
	address space mutex. It's just a first try. More reflexion has to
	be made.

	* modules/task/task.h: Make sure DOXYGEN doesn't try to analyze
	the #if stuff, because it doesn't like it.

	* modules/task/_task_utils.c (show_all_thread_info): If team is
	NULL, it means that we want to display the threads of all teams.

	* modules/scheduler/synchq.h: Avoid inclusion of task.h.

	* modules/pmm/pmm.c: New PMM system.

	* modules/pmm/_pmm_put_page.c: New PMM system.

	* modules/pmm/_pmm_init.c: New PMM system.

	* modules/pmm/_pmm_get_page.c: New PMM system.

	* modules/pmm/_pmm_get_at_addr.c: New PMM system.

	* modules/pmm/_pmm.h: struct gpfme is now private.

	* modules/pmm/pmm.h: struct gpfme is now private (migrated to
	_pmm.h). 

	* modules/pmm/Makefile (OBJS): New PMM system, with fewer
	functionnalities. 

	* modules/kos/spinlock.h: New type spinlock_flags_t, that should
	be used instead of k_ui32_t for spinlock flags.

	* modules/kmem/_kvmem_utils.c: Migration to the new PMM
	system and various cleanups.

	* modules/kmem/_kvmem_init.c: Migration to the new PMM
	system and various cleanups.

	* modules/kmem/_kslab_cache_grow.c: Migration to the new PMM
	system and various cleanups.

	* modules/kmem/_kslab_cache_free.c: Migration to the new PMM
	system, and various cleanups.

	* modules/kitc/_kmutex.c: DEBUG_PRINT3 calls to show mutex
	lock/unlock/trylock.

	* modules/init/_init_modules.c (init_modules): A message is
	displayed when initializating modules.

	* modules/ide/_ide.c: Various cleanups.

	* modules/fs/fat/_fat.c: Various cleanups.

	* modules/fs/devfs/devfs.c: Various cleanups, including whitespace
	cleanification.

	* modules/debug/debug.h: Add the DEBUG_PRINT1, DEBUG_PRINT2,
	DEBUG_PRINT3 macros. Maybe there's a cleaner way to do it. David ?

	* modules/debug/debug.c (init_module_level0): Init the
	backtracking stuff a little later so that we have debugging
	messages during this initialization.

	* modules/debug/bt.c (_init_backtracing_stuff): bt_next is not
	anymore a valid candidate to determine if fomit-frame-pointer was
	selected or not, because of gcc optimizations. We use bt_init
	instead.

	* modules/Makefile (doc): Add a target that generates the doxygen
	documentation. 

	* loader/mod.h (EXPORT_FUNCTION_RESTRICTED): Change the symbol
	names generated by the macros, so that they include the name of
	the target module (the one allowed to import the exported
	symbol). This is needed in order to export the same symbol to
	multiple modules. Previously, the RESTRICTED system generated
	symbols that were identical for a given symbol exported to
	multiple modules.

	* doc/testingfr.tex: A big update to this documentation. Not
	finished. The english version should also be updated.

	* TODO: Some new things to do.

	* MkVars (CFLAGS): Pass the DEBUG_LEVEL Makefile variable to the C
	files. In each modules/.../Makefile, we can set a
	DEBUG_LEVEL=value that will set the level of verbosity of the
	module. Macros named DEBUG_PRINT1, DEBUG_PRINT2, DEBUG_PRINT3 have
	been added.
	(MODULES): Change all '-' to '_', because of the new
	EXPORT_FUNCTION_RESTRICTED system. This system creates symbol that
	contains the name of a module (the one allowed to import the
	exported symbol). But the '-' character is not allowed inside C
	identifiers. So, we use '_' instead.

	* CREDITS: Add Fabrice Bellard to the CREDITS, for his Qemu
	emulator.



Index: _rmap.c
===================================================================
RCS file: /var/cvs/kos/kos/modules/x86/mm/_rmap.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- _rmap.c	18 Aug 2003 17:05:34 -0000	1.13
+++ _rmap.c	28 Dec 2004 18:45:02 -0000	1.14
@@ -1,502 +1,507 @@
-#include <kmem/kmem.h>
-#include <kos/assert.h>
-#include <kos/macros.h>
-#include <kos/spinlock.h>
-#include <lib/list/liblist.h>
+/**@file
+ * Reverse mapping management procedures
+ *
+ * <b>Why do we need reverse mapping ?</b>
+ *
+ * The x86 MMU needs page tables and page directories to translate
+ * virtual addressees to physical addresses. These structures are
+ * mandatory and their format are determined by the architecture.
+ *
+ * When you want to swap a page, you need to unmap it everywhere it is
+ * mapped to make sure that future accesses of the page will generate
+ * a page fault exception. The easiest way of unmapping a page
+ * everywhere it is mapped is to have, for each physical page, the
+ * list of the locations in which it is mapped.
+ *
+ * The procedures in this file allows to maintains such lists. Each
+ * physical page (represented by a struct gpfme) contains a list of
+ * struct rmap. Each struct rmap correspond to one virtual mapping of
+ * the physical page.
+ *
+ * You might also wonder why we maintain reverse mapping entries for
+ * the kernel pages, because we will never swap them out. Maintaining
+ * these entries also allows to move the data of all physical pages to
+ * an other physical page. This allows to free some physical space at
+ * arbitrary addresses, which is a useful feature when dealing with
+ * DMA limited devices (for example that requires 64 Kb physically
+ * contiguous physical space below the 16 MB limit, which is the case
+ * for old ISA devices).
+ *
+ * <b>The initialization process</b>
+ *
+ * When mapping a page, we need to add a struct rmap structure to the
+ * list of reverse mapping. So we must allocate memory to store this
+ * structure, but allocation is not possible at the early stages of
+ * the initialization because kmalloc() is not yet ready.
+ *
+ * The functions inside the _vmap.c files do not call directly the
+ * functions in this file. Instead they use the rmap_ops structure,
+ * that contains function pointer for the 4 needed operations :
+ *  - struct rmap allocation
+ *  - struct rmap liberation
+ *  - add an rmap to an rmap list
+ *  - remove an rmap from an rmap list
+ *
+ * These operations are statically initialized to point to the
+ * <i>noop</i> functions (_alloc_struct_rmap_noop(),
+ * _free_struct_rmap_noop(), _add_rmapping_noop(),
+ * _del_rmapping_noop()). These <i>noop</i> functions don't make
+ * anything.
+ *
+ * Once initialization of the kernel memory allocator is done, the
+ * _rmap_init() function gets called. This function changes the
+ * operations in rmap_ops so that future rmapping operations will use
+ * the correct functions, and then builds the missing reverse mapping
+ * entries.
+ *
+ * <b>Why do we use a get/commit scheme to update the reverse mapping
+ * list and not a simple add/remove scheme ?</b>
+ *
+ * @see _pmm_rmap.c
+ *
+ * We could have implemented two functions nammed
+ * <i>physmem_rmap_add</i> and <i>physmem_rmap_del</i> to add and
+ * remove reverse mapping entries for the lists. We didn't did that
+ * because :
+ *
+ * - The pmm module (in which these functions could have been
+ *   implemented) has no knowledge of the internal structure of
+ *   struct rmap. So it doesn't know where the next field is and
+ *   can't build linked list.
+ *
+ * - To delete a reverse mapping entry, we must travel the list to
+ *   find the rmap entry that corresponds to the information
+ *   (index_team, index_pde, index_pte, is_pt). Passing them to a
+ *   function in the pmm module is not conceptually clean, because
+ *   these informations heavily rely on the x86 architecture, which
+ *   pmm is independent from. An other solution would have been to
+ *   pass a traveler function to the pmm module that tells whether two
+ *   rmap entries corresponds to the same page. This would work, but
+ *   wouldn't solve the fact that the 'next' field is not known from
+ *   the pmm module.
+ *
+ * @author Thomas Petazzoni
+ * @author David Decotigny
+ */
 
-/* I know it's forbidden to include private headers, but here, I think
-   it's much better to include a private file that putting in the
-   public header things that are only needed here, such as
-   chained_page_range. */
-#include <kmem/_kvmem.h>
+#include <kos/macros.h>
+#include <kmem/kmem.h>
 
 #include "_mm.h"
 
-static struct kslab_cache *_rmap_cache;
-
-static int _nop_pre_add_rmapping(struct rmap_session_s *rmap_session);
-static int _nop_do_add_rmapping(struct rmap_session_s *rmap_session,
-				k_ui32_t index_team, gpfme_t *gpfme, 
-				vaddr_t virt, bool_t is_pt);
-static int _nop_post_add_rmapping(struct rmap_session_s *);
-
-static int _nop_pre_del_rmapping(struct rmap_session_s *rmap_session);
-static int _nop_do_del_rmapping(struct rmap_session_s *rmap_session,
-				k_ui32_t index_team, gpfme_t *gpfme, 
-				vaddr_t virt);
-static int _nop_post_del_rmapping(struct rmap_session_s *);
-
-/***********************************************************************
- * Initial rmap operations, used until the kslab is initialised:
- * only update the reference counters
+/** The cache used to allocate the reverse mapping structures
+ *
+ * It remains NULL during the early stages of the initialization,
+ * because at that time, slab allocation is not possible.
+ *
+ * Then the arch_rmap_init() function will be called, and will
+ * allocate the cache, so that arch_pre_map, arch_post_map,
+ * arch_pre_unmap, arch_post_unmap can really do their job. As they
+ * couldn't do it before, the rmap structures that hadn't been
+ * allocated will get created during arch_rmap_init().
  */
-struct _rmap_ops_s _rmap_ops = {
-  _nop_pre_add_rmapping,
-  _nop_do_add_rmapping,
-  _nop_post_add_rmapping,
-
-  _nop_pre_del_rmapping,
-  _nop_do_del_rmapping,
-  _nop_post_del_rmapping
-};
-
-
-__init_text static int
- _nop_pre_add_rmapping(struct rmap_session_s *rmap_session)
-{
-  UNUSED(rmap_session);
-  return 0;
-}
+static struct kslab_cache *_rmap_structs_cache = NULL;
 
+/*
+ * Functions used during initialization
+ */
 
-__init_text static int
-_nop_do_add_rmapping(struct rmap_session_s *rmap_session,
-		     k_ui32_t index_team, gpfme_t *gpfme, 
-		     vaddr_t virt, bool_t is_pt)
+/** The struct rmap allocation function used during initialization
+ *
+ * It does nothing.
+ *
+ * @return Always 1, so that the caller "thinks" that the allocation
+ * was successful.
+ */
+static struct rmap *_alloc_struct_rmap_noop(void)
 {
-  UNUSED(rmap_session);
-  UNUSED(index_team);
-  UNUSED(is_pt);
-
-  CONCEPTION_ASSERT(gpfme && virt);
-
-  CONCEPTION_ASSERT(gpfme->mapping_list == NULL);
-  gpfme->ref_cnt ++;
-
-  return 0;
+  return (struct rmap *) 1;
 }
 
-__init_text static int
-_nop_post_add_rmapping(struct rmap_session_s *rmap_session)
+/** The struct rmap liberation function used during initialization.
+ *
+ * It does nothing.
+ *
+ * @param r The reverse mapping entry
+ *
+ * @return ESUCCESS (always successful).
+ */
+static result_t _free_struct_rmap_noop(struct rmap *r)
 {
-  UNUSED(rmap_session);
-  return 0;
+  UNUSED(r);
+  return ESUCCESS;
 }
 
-__init_text static int
-_nop_pre_del_rmapping(struct rmap_session_s *rmap_session)
+/** The reverse mapping entry add function used during initialization
+ *
+ * It does nothing.
+ *
+ * @param paddr The physical address of the page for which a new
+ * reverse mapping entry should be added
+ *
+ * @param r The reverse mapping structure
+ *
+ * @param index_team The index of the team in the PD table mapper
+ *
+ * @param index_pde The index of the PDE that corresponds to the page
+ *
+ * @param index_pte The index of the PTE that corresponds to the page
+ *
+ * @param is_pt A boolean that indicates whether the reverse mapping
+ * entry correspond to a normal page or a page table page
+ *
+ * @return ESUCCESS (always successful)
+ */
+static result_t _add_rmapping_noop(paddr_t paddr, struct rmap *r, int index_team,
+				   int index_pde, int index_pte, bool_t is_pt)
 {
-  UNUSED(rmap_session);
-  return 0;
+  UNUSED(paddr);
+  UNUSED(r);
+  UNUSED(index_team);
+  UNUSED(index_pde);
+  UNUSED(index_pte);
+  UNUSED(is_pt);
+  return ESUCCESS;
 }
 
-__init_text static int
-_nop_do_del_rmapping(struct rmap_session_s *rmap_session,
-		     k_ui32_t index_team, gpfme_t *gpfme, 
-		     vaddr_t virt)
+/** The reverse mapping entry remove function used during initialization
+ *
+ * It does nothing
+ *
+ * @param paddr The physical address of the page in which a reverse
+ * mapping entry has to be removed.
+ *
+ * @param index_team The index of the team in the PD table mapper
+ *
+ * @param index_pde The index of the PDE that corresponds to the page
+ *
+ * @param index_pte The index of the PTE that corresponds to the page
+ *
+ * @param is_pt A boolean that indicates whether the reverse mapping
+ * entry correspond to a normal page or a page table page
+ *
+ * @param out The address at which a pointer to the removed reverse
+ * mapping entry is returned.
+ *
+ * @result ESUCCESS (always successful)
+ */
+static result_t _del_rmapping_noop(paddr_t paddr, int index_team, int index_pde,
+				   int index_pte, bool_t is_pt, struct rmap **out)
 {
+  UNUSED(paddr);
   UNUSED(index_team);
-  UNUSED(rmap_session);
-
-  CONCEPTION_ASSERT(gpfme && virt);
-  CONCEPTION_ASSERT((gpfme->ref_cnt > 0)
-		    && (gpfme->mapping_list == NULL));
-  gpfme->ref_cnt --;
-
-  return 0;
+  UNUSED(index_pde);
+  UNUSED(index_pte);
+  UNUSED(is_pt);
+  UNUSED(out);
+  return ESUCCESS;
 }
 
+/*
+ * Real functions
+ */
 
-__init_text static int
-_nop_post_del_rmapping(struct rmap_session_s *rmap_session)
+/** The struct rmap allocation function used after initialization
+ *
+ * Simply use the slab allocator to allocate a reverse mapping
+ * structure (struct rmap) inside the _rmap_structs_cache cache.
+ *
+ * @return The address of the newly allocated reverse mapping entry
+ */
+static struct rmap *_alloc_struct_rmap_real(void)
 {
-  UNUSED(rmap_session);
-  return 0;
+  return kslab_cache_alloc(_rmap_structs_cache);
 }
 
-
-/***********************************************************************
- * Real rmap operations: called once kslab is initialised
+/** The struct rmap liberation function used after initialization.
+ *
+ * Simply frees the reverse mapping structure (struct rmap) into the
+ * _rmap_structs_cache cache.
+ *
+ * @param r The reverse mapping entry
+ *
+ * @return Error code.
  */
+static result_t _free_struct_rmap_real(struct rmap *r)
+{
+  return kslab_cache_free(_rmap_structs_cache, r);
+}
 
-/*
- * Some explanations concerning rmap_session and prepare/do/end
- * add/del callbacks
+/** The reverse mapping entry add function used during initialization
  *
- * Problem description: basically, these callbacks can ONLY be called
- * by vmap. During the vmap operations, the gpfm, and the mm_context
- * or kernel_space locks are owned by the calling thread. BUT, the
- * rmap need new rmap structures, which implies calling the kslab
- * facilities. BUT the kslab relies on the vmap. So that we have the
- * following deadlock in the case the original page to be mapped was a
- * kernel page: vmap -> lock(kernel_space) -> rmap -> kslab -> vmap ->
- * lock(kernel_space)
+ * This function adds a reverse mapping entry to the physical page
+ * designated by paddr. The reverse mapping entry is filled using the
+ * given index_team, index_pde, index_pte and is_pt informations.
  *
- * Possibile solutions:
- * - call the rmap functions outside the lock => BAD idea because the
- *   swapper might appear between a new page vmap'ped and the page
- *   being rmap'ped => the swapper won't be able to consider the new
- *   page.
- * - Create a rmap pool management API. This is redundant with the
- *   kslab, and does not avoid the deadlock problem, because any new
- *   pool page that needs be allocated, needs also be vmap'ped...
- * - "pre-allocate" the rmap structures BEFORE the lock, and release
- *   any unused rmap after the rmap_add/del and after the lock.
+ * First of all, this function gets the current head of the reverse
+ * mapping list of the physical page. Then, it initializes the given
+ * reverse mapping structure with the given informations. Then, it
+ * adds this reverse mapping structure to the list, and commits the
+ * new head of the list to the physical page.
  *
- * => We implemented the last approach.
+ * @param paddr The physical address of the page for which a new
+ * reverse mapping entry should be added
  *
- * Implementation considerations:
- * - vmap needs at most allocate a normal page AND a PT while holding
- *   the lock. Never more, maybe less (PT unused).
- * - It would be unadapted to always pre-allocate the rmaps for both
- *   the page AND the potential PT to allocate, precisely because a
- *   new PT is scarcely needed => we use the spare_pt_rmap rmap data
- *   to store any previously allocated but unused PT rmap structure.
+ * @param r The reverse mapping structure
+ *
+ * @param index_team The index of the team in the PD table mapper
+ *
+ * @param index_pde The index of the PDE that corresponds to the page
+ *
+ * @param index_pte The index of the PTE that corresponds to the page
+ *
+ * @param is_pt A boolean that indicates whether the reverse mapping
+ * entry correspond to a normal page or a page table page
+ *
+ * @return ESUCCESS (always successful)
  */
-
-static SPINLOCK(spare_pt_rmap_lock);
-static struct mapping_s* spare_pt_rmap = NULL;
-
-static int
-_pre_add_rmapping(struct rmap_session_s *rmap_session)
+static result_t _add_rmapping_real(paddr_t paddr, struct rmap *r, int index_team,
+				   int index_pde, int index_pte, bool_t is_pt)
 {
-  k_ui32_t flags;
-
-  CONCEPTION_ASSERT(rmap_session);
+  struct rmap *list;
+  spinlock_flags_t flags;
+  result_t result;
 
-  /* If any spared PT rmapping is available, use it (this prevents
-     from allocating another one) */
-  write_spin_lock(spare_pt_rmap_lock, flags);
-  rmap_session->pt_rmap = spare_pt_rmap;
-  spare_pt_rmap = NULL;
-  write_spin_unlock(spare_pt_rmap_lock, flags);
+  DEBUG_PRINT2("[%d:%d] Adding rmap for %s phys=0x%x, virt=0x%x\n",
+	       index_pde, index_pte, (is_pt ? "PT" : "Page"),
+	       paddr, (index_pde * 1024 * PAGE_SIZE + index_pte * PAGE_SIZE));
 
-  /* If spare PT rmap was not available, allocate one */
-  if (rmap_session->pt_rmap == NULL)
-    rmap_session->pt_rmap = kslab_cache_alloc(_rmap_cache);
+  /* Get the current rmapping list */
+  result = physmem_get_rmapping_list(paddr, & list, & flags);
+  ASSERT_FATAL(result == ESUCCESS);
 
-  /* Allways get a "normal" page mapping */
-  rmap_session->page_rmap = kslab_cache_alloc(_rmap_cache);
+  r->index_team = index_team;
+  r->index_pde  = index_pde;
+  r->index_pte  = index_pte;
+  r->is_pt      = is_pt;
+  r->next       = list;
+  list          = r;
 
-  CONCEPTION_ASSERT(rmap_session->pt_rmap && rmap_session->page_rmap);
+  /* Commit the new list, and increment the reference counter by one */
+  result = physmem_commit_rmapping_list(paddr, list, flags, 1);
+  ASSERT_FATAL(result == ESUCCESS);
 
-  return 0;
+  return ESUCCESS;
 }
 
-
-static int
-_do_add_mapping(struct rmap_session_s *rmap_session,
-		k_ui32_t index_team, gpfme_t *gpfme, 
-		vaddr_t virt, bool_t is_pt)
+/** The reverse mapping entry remove function used during initialization
+ *
+ * This functions removes the reverse mapping entry that corresponds
+ * to the given index_team, index_pde, index_pte and is_pt from the
+ * physical page at address paddr.
+ *
+ * First of all, it gets the current head of the reverse mapping
+ * entries list of the physical page. Then, it travels through this
+ * list to find the entry that correspond to the given
+ * informations. Then, the found entry is removed from the list, and
+ * the new head of the list is committed back to the physical page.
+ *
+ * @param paddr The physical address of the page in which a reverse
+ * mapping entry has to be removed.
+ *
+ * @param index_team The index of the team in the PD table mapper
+ *
+ * @param index_pde The index of the PDE that corresponds to the page
+ *
+ * @param index_pte The index of the PTE that corresponds to the page
+ *
+ * @param is_pt A boolean that indicates whether the reverse mapping
+ * entry correspond to a normal page or a page table page
+ *
+ * @param out The address at which a pointer to the removed reverse
+ * mapping entry is returned.
+ *
+ * @result ESUCCESS (always successful)
+ */
+static result_t _del_rmapping_real(paddr_t paddr, int index_team, int index_pde,
+				   int index_pte, bool_t is_pt, struct rmap **out)
 {
-  struct mapping_s* rmap;
-
-  CONCEPTION_ASSERT(rmap_session && gpfme && virt);
-
-  /* Retrieve the right rmap to update from the rmap_session structure */
-  if (is_pt)
-    {
-      CONCEPTION_ASSERT(rmap_session->pt_rmap);
-      rmap = rmap_session->pt_rmap;
-      rmap_session->pt_rmap = NULL; /* mark it as used */
-    }
-  else
-    {
-      CONCEPTION_ASSERT(rmap_session->page_rmap);
-      rmap = rmap_session->page_rmap;
-      rmap_session->page_rmap = NULL; /* mark it as used */
-    }
-
-  CONCEPTION_ASSERT(rmap);
-
-  /* Actually update the rmap */
-  rmap->index_team = index_team;
-  rmap->index_pde  = va_to_pde(virt);
-  rmap->index_pte  = va_to_pte(virt);
-  rmap->is_pt      = is_pt;
-  rmap->next       = NULL;
-  
-  /* Add the new rmap to the gpfme */
-  gpfme->ref_cnt++;
-  if(gpfme->mapping_list != NULL)
-    rmap->next = gpfme->mapping_list;
-  gpfme->mapping_list = rmap;
-
-  return 0;
-}
+  struct rmap *list, *cur, *prev;
+  spinlock_flags_t flags;
+  result_t result;
 
+  DEBUG_PRINT2("[%d:%d] Deleting rmap for %s phys=0x%x, virt=0x%x\n",
+	       index_pde, index_pte, (is_pt ? "PT" : "Page"),
+	       paddr, (index_pde * 1024 * PAGE_SIZE + index_pte * PAGE_SIZE));
 
-static int
-_post_add_rmapping(struct rmap_session_s *rmap_session)
-{
-  k_ui32_t flags;
-  CONCEPTION_ASSERT(rmap_session);
+  /* Get the current rmapping list */
+  result = physmem_get_rmapping_list(paddr, & list, & flags);
+  ASSERT_FATAL(result == ESUCCESS);
 
-  /* Reclaim unused PT rmap: if spare_pt_rmap is free, don't free the
-     PT rmap => assign it to spare_pt_rmap instead for future use by
-     another add_rmapping */
-  if (rmap_session->pt_rmap)
+  /* Find the reverse mapping entry that corresponds to the given
+     informations (index_team, index_pde, index_pte, is_pt). We can't
+     use the list_foreach() macro because the list is a single-linked
+     list. For the same reason, we have to maintain both a pointer to
+     the current element (cur) and a pointer to the previous element
+     (prev) */
+  for (cur = list, prev = NULL ;
+       cur != NULL ;
+       prev = cur, cur = cur->next)
     {
+      DEBUG_PRINT2("Comparing (%d %d %d %d) with (%d %d %d %d)\n",
+		   cur->index_team, cur->index_pde, cur->index_pte, cur->is_pt,
+		   index_team, index_pde, index_pte, is_pt);
 
-      /* Try to assign the PT rmap to release to the spare PT */
-      write_spin_lock(spare_pt_rmap_lock, flags);
-      if (spare_pt_rmap == NULL)
-	{
-	  /* Ok, assign unused PT rmap to spare PT */
-	  spare_pt_rmap = rmap_session->pt_rmap;
-	  rmap_session->pt_rmap = NULL;
-	}
-      /* else: release unused PT rmap manually -> see below */
-      write_spin_unlock(spare_pt_rmap_lock, flags);
-
-      /* If spare PT rmap was already assigned, free the current PT rmap */
-      if (rmap_session->pt_rmap != NULL)
-	kslab_cache_free(_rmap_cache, rmap_session->pt_rmap);
-    }
-
-  /* Should never occur (the _do_add_mapping() should normally have
-     always been called between _pre_add/_post_add, so that the
-     "normal" page_rmap is always used */
-  if (rmap_session->page_rmap)
-    {
-      write_spin_lock(spare_pt_rmap_lock, flags);
-      if (spare_pt_rmap == NULL)
+      if((cur->index_team == index_team) &&
+	 (cur->index_pde  == index_pde)  &&
+	 (cur->index_pte  == index_pte)  &&
+	 (cur->is_pt      == is_pt))
 	{
-	  /* Ok, assign unused rmap to spare PT */
-	  spare_pt_rmap = rmap_session->page_rmap;
-	  rmap_session->page_rmap = NULL;
+	  break;
 	}
-      /* else: release unused PT rmap manually -> see below */
-      write_spin_unlock(spare_pt_rmap_lock, flags);
-
-      if (rmap_session->page_rmap)
-	kslab_cache_free(_rmap_cache, rmap_session->page_rmap);
     }
 
-  return 0;
-}
-
-
-static int
-_pre_del_rmapping(struct rmap_session_s *rmap_session)
-{
-  CONCEPTION_ASSERT(rmap_session);
-
-  /* Indicate that none is to be freed by the _post_del_rmap() */
-  rmap_session->page_rmap = NULL;
-  rmap_session->pt_rmap   = NULL;
-
-  return 0;
-}
-
-static int _do_del_mapping(struct rmap_session_s *rmap_session,
-			   k_ui32_t index_team, gpfme_t *gpfme,
-			   vaddr_t virt)
-{
-  struct mapping_s *current, *prev;
-  int index_pde, index_pte;
-
-  CONCEPTION_ASSERT(rmap_session && gpfme && virt);
-
-  index_pde = va_to_pde(virt);
-  index_pte = va_to_pte(virt);
-
-  CONCEPTION_ASSERT(gpfme->ref_cnt > 0);
-
-  prev = NULL;
-  for ( current = gpfme->mapping_list ;
-	current != NULL ;
-	prev = current, current = current->next)
-    if ( (current->index_team == index_team)
-	 && (current->index_pde == index_pde)
-	 && (current->index_pte == index_pte) )
-      break;
-
-  /* We did not find the requested mapping ! */
-  CONCEPTION_ASSERT(current);
-
-  /* Del the mapping */
-  if (prev != NULL)
-    prev->next = current->next;
-  else
-    gpfme->mapping_list = current->next;
+  /* A reverse mapping entry must be found, because if the page is
+     mapped, a reverse mapping entry exists */
+  ASSERT_FATAL(cur != NULL);
 
-  gpfme->ref_cnt --;
+  /* Returns the address of the reverse mapping structure */
+  *out = cur;
 
-  /* Mark the rmap structure to be freed by _post_del_rmap() */
-  if (current->is_pt) 
+  /* Removes the reverse mapping entry from the list */
+  if(prev != NULL)
     {
-      CONCEPTION_ASSERT(rmap_session->pt_rmap == NULL);
-      rmap_session->pt_rmap = current;
+      prev->next = cur->next;
     }
   else
     {
-      CONCEPTION_ASSERT(rmap_session->page_rmap == NULL);
-      rmap_session->page_rmap = current;
-    }
-
-  return 0;
-}
-
-/* Actually delete any "marked to be deleted" PT/page rmap */
-static int
-_post_del_rmapping(struct rmap_session_s *rmap_session)
-{
-  CONCEPTION_ASSERT(rmap_session);
-
-  /* The rmap_session's PT is to be deleted */
-  if (rmap_session->pt_rmap)
-    {
-      k_ui32_t flags;
-
-      /* Try to assign the PT rmap to release to the spare PT */
-      write_spin_lock(spare_pt_rmap_lock, flags);
-      if (spare_pt_rmap == NULL)
-	{
-	  /* Ok, assign PT rmap to spare PT */
-	  spare_pt_rmap = rmap_session->pt_rmap;
-	  rmap_session->pt_rmap = NULL;
-	}
-      /* else: release PT rmap manually -> see below */
-      write_spin_unlock(spare_pt_rmap_lock, flags);
-
-      /* If spare PT rmap was already assigned, free the current PT rmap */
-      if (rmap_session->pt_rmap != NULL)
-	kslab_cache_free(_rmap_cache, rmap_session->pt_rmap);
+      list = cur->next;
     }
 
-  /* The normal page rmap is to be deleted */
-  if (rmap_session->page_rmap)
-    kslab_cache_free(_rmap_cache, rmap_session->page_rmap);
+  /* Commit the new list, and decrement the reference counter by one */
+  result = physmem_commit_rmapping_list(paddr, list, flags, -1);
+  ASSERT_FATAL(result == ESUCCESS);
 
-  return 0;
+  return ESUCCESS;
 }
 
-/* When gpfme not mapped (but set to ref_cnt=1 in _pmm_init), return
-   the physical address of the page for it to be further
-   suppressed. Or return 0 (mapped Ok, or not mapped). */
-__init_text static int _check_empty(gpfme_t* gpfme, void* custom_param)
+#if (DEBUG_LEVEL > 2)
+result_t arch_rmap_list_display(paddr_t paddr)
 {
-  UNUSED(gpfme);
-  UNUSED(custom_param);
-
-  if (gpfme->ref_cnt == 0)
-    /* Nobody */
-    return 0;
-
-  if (gpfme->mapping_list)
-    /* Ok, correcly rmapped */
-    return 0;
-
-  WARNING(_B_RED "gpfme for paddr=0x%x, type=%d, swap_status=%d, ref_cnt=%d not rmapped => suppression in progress\n" _B_NORM,
-	  gpfme->address, gpfme->flags.page_type,
-	  gpfme->flags.swap_status, gpfme->ref_cnt);
+  struct rmap *list, *cur, *prev;
+  spinlock_flags_t flags;
+  result_t result;
 
-  /* Mark gpfme to be suppressed */
-  gpfme->ref_cnt = 0;
-  return gpfme->address;
-}
+  /* Get the current rmapping list */
+  result = physmem_get_rmapping_list(paddr, & list, & flags);
+  ASSERT_FATAL(result == ESUCCESS);
 
-__init_text static int _rmap_update_vpage(vaddr_t vaddr, bool_t is_pt)
-{
-  gpfme_t* gpfme;
-  k_ui32_t flags;
-  struct rmap_session_s rmap_session;
-  
-  _rmap_ops.pre_add_rmapping(& rmap_session);
+  DEBUG_PRINT3(" | Listing rmaps for physical page 0x%x\n", paddr);
 
-  gpfme = get_gpfme_at_virt_addr(vaddr, & flags);
-  if ((!gpfme) || (gpfme->mapping_list != NULL))
+  for (cur = list, prev = NULL ;
+       cur != NULL ;
+       prev = cur, cur = cur->next)
     {
-      gpfme_unlock(gpfme, & flags);
-      _rmap_ops.post_add_rmapping(& rmap_session);
-      return 0;
+      DEBUG_PRINT3("  + Virt = 0%x in team %d (%s)\n",
+		   ((cur->index_pde * 1024 * PAGE_SIZE) + (cur->index_pte * PAGE_SIZE)),
+		   cur->index_team,
+		   (cur->is_pt ? "PT" : "Page"));
     }
 
-  /* Got one */
-  _rmap_ops.do_add_rmapping(& rmap_session, PRIMARY_TEAM_PD_ID, gpfme,
-			    vaddr, is_pt);
-  gpfme->ref_cnt = 1;
-  gpfme_unlock(gpfme, & flags);
-  _rmap_ops.post_add_rmapping(& rmap_session);
+  /* Commit the new list, and decrement the reference counter by one */
+  result = physmem_commit_rmapping_list(paddr, list, flags, -1);
+  ASSERT_FATAL(result == ESUCCESS);
 
-  return 0;
+  return ESUCCESS;
 }
+#endif
 
-/*
- * Assumes that called during the init phase (no lock acquired !!!)
+/** The reverse mapping operations structure
+ *
+ * This structure contains pointers to the operations needed to
+ * manipulate reverse mapping entries.
  */
-__init_text static int _rmap_update_kernel_area(void)
+struct rmap_ops rmap_ops =
+  {
+    _alloc_struct_rmap_noop,
+    _free_struct_rmap_noop,
+    _add_rmapping_noop,
+    _del_rmapping_noop
+  };
+
+/** Initializes the reverse mapping mechanism
+ *
+ * Before the call to this function, no reverse mapping entries are
+ * allocated nor added to the lists, because the kernel memory
+ * allocator is not present. This is the time where noop operations
+ * are used.
+ *
+ * This functions creates the cache that will be used to allocate
+ * reverse mapping entries. Then it scans all PTs of the kernel to
+ * create the missing reverse mapping entries. Finally, it sets the
+ * function pointers of the rmap_ops structure to the real functions.
+ *
+ * @return ESUCCESS
+ */
+__init_text result_t _rmap_init(void)
 {
-  int i;
-  vaddr_t vaddr;
-  paddr_t ppage_to_suppress;
-  struct chained_page_range *page_range;
-  
+  int i, j;
+
+  /* Make sure we have enough margin to eventually allocate 2 pages :
+     one for an enlargement of the rmap slab cache, one for an
+     eventual PT associated with it. */
+#define RMAP_SLAB_MARGIN 16 /* 2 should be enough. 16 is also fine ;) */
+  _rmap_structs_cache = kslab_cache_create("rmap", sizeof(struct rmap), 0, 0,
+					   RMAP_SLAB_MARGIN);
+
   /* We only check the 512 first entries, since we are at the
      beginning of the initialisation, there's not PT in the user space */
   for (i = 0 ; i < 512 ; i++)
     {
       page_entry_t *pd = (page_entry_t*) CURRENT_PD_VADDR;
+      page_entry_t *pt;
+      vaddr_t vaddr;
+      paddr_t pt_paddr;
+      struct rmap *rmap;
+      result_t result;
+      count_t use_cnt;
 
       if(IS_UNMAPPED(pd[i]))
 	continue;
-  
+
       vaddr = CURRENT_PT_AREA_START + i*PAGE_SIZE;
-      _rmap_update_vpage(vaddr, TRUE);
-    }
 
-  /* For each used range of the kvmem list, we add all pages */
-  list_foreach(__kvmem_get_used_page_range_list(), page_range, i)
-    {
-      for (vaddr = page_range->start;
-	   vaddr < (page_range->start + page_range->nb_pages * PAGE_SIZE);
-	   vaddr += PAGE_SIZE)
-	{
-	  _rmap_update_vpage(vaddr, FALSE);
-	}
-    }
+      rmap = kslab_cache_alloc(_rmap_structs_cache);
+      ASSERT_FATAL(rmap != NULL);
 
-  /* Free any unmapped gpfme */
-  do {
-    ppage_to_suppress = 
-      _gpfm_visit_list_unsafe(PHYS_PAGE_USER, _check_empty, NULL);
-    if (ppage_to_suppress != 0)
-      put_physical_page(ppage_to_suppress);
-  } while (ppage_to_suppress != 0);
+      result = arch_get_paddr_at_vaddr(NULL, vaddr, & pt_paddr);
+      ASSERT_FATAL(result == ESUCCESS);
 
-  do {
-    ppage_to_suppress = 
-      _gpfm_visit_list_unsafe(PHYS_PAGE_KERNEL, _check_empty, NULL);
-    if (ppage_to_suppress != 0)
-      put_physical_page(ppage_to_suppress);
-  } while (ppage_to_suppress != 0);
+      _add_rmapping_real(pt_paddr, rmap, PRIMARY_TEAM_PD_ID,
+			 va_to_pde(vaddr), va_to_pte(vaddr), TRUE);
 
-  do {
-    ppage_to_suppress = 
-      _gpfm_visit_list_unsafe(PHYS_PAGE_HW_MAPPING, _check_empty, NULL);
-    if (ppage_to_suppress != 0)
-      put_physical_page(ppage_to_suppress);
-  } while (ppage_to_suppress != 0);
+      pt = (page_entry_t*) vaddr;
+      use_cnt = 0;
 
-  return 0;
-}
+      for (j = 0 ; j < 1024 ; j++)
+	{
+	  paddr_t paddr;
 
+	  if(i >= CURRENT_PT_AREA_INDEX)
+	    break;
 
-__init_text int _rmap_init(kernel_parameter_t *kp)
-{
-  UNUSED(kp);
+	  if(IS_UNMAPPED(pt[j]))
+	    continue;
 
-  /* Make sure we have enough margin to eventually allocate 2 pages :
-     one for an enlargement of the rmap slab cache, one for an
-     eventual PT associated with it. */
-#define RMAP_SLAB_MARGIN 16 /* 2 should be enough. 16 is also fine ;) */
-  _rmap_cache = kslab_cache_create("rmap", sizeof(struct mapping_s), 0, 0,
-				   RMAP_SLAB_MARGIN);
+	  vaddr = (i * 1024 * PAGE_SIZE) + (j * PAGE_SIZE);
 
-  if (_rmap_cache == NULL)
-    FAILED_VERBOSE("(init_rmap) _rmap.c allocation failed\n");
+	  use_cnt++;
+	  rmap = kslab_cache_alloc(_rmap_structs_cache);
+	  ASSERT_FATAL(rmap != NULL);
 
-  _rmap_ops.pre_add_rmapping  = _pre_add_rmapping;
-  _rmap_ops.do_add_rmapping   = _do_add_mapping;
-  _rmap_ops.post_add_rmapping = _post_add_rmapping;
+	  arch_get_paddr_at_vaddr(NULL, vaddr, & paddr);
 
-  _rmap_ops.pre_del_rmapping  = _pre_del_rmapping;
-  _rmap_ops.do_del_rmapping   = _do_del_mapping;
-  _rmap_ops.post_del_rmapping = _post_del_rmapping;
-  
-  _rmap_update_kernel_area();
+	  _add_rmapping_real(paddr, rmap, PRIMARY_TEAM_PD_ID,
+			     va_to_pde(vaddr), va_to_pte(vaddr), FALSE);
+	}
 
-  return 0;
-}
+      physmem_set_use_cnt(pt_paddr, use_cnt);
+    }
+
+  rmap_ops.alloc = _alloc_struct_rmap_real;
+  rmap_ops.free  = _free_struct_rmap_real;
+  rmap_ops.add   = _add_rmapping_real;
+  rmap_ops.del   = _del_rmapping_real;
 
+  return ESUCCESS;
+}

Index: _mm.h
===================================================================
RCS file: /var/cvs/kos/kos/modules/x86/mm/_mm.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- _mm.h	21 Aug 2003 23:19:29 -0000	1.10
+++ _mm.h	28 Dec 2004 18:45:02 -0000	1.11
@@ -7,6 +7,8 @@
 #include <pmm/pmm.h>
 #include <loader/mod.h>
 
+#include "mm.h"
+
 /* Index of the PD for the very primitive primary first team */
 #define PRIMARY_TEAM_PD_ID 0
 
@@ -20,7 +22,7 @@
 
 /* The two following defines are not imposed by Intel PTE format, but
    we only chose to use bit 9 to mark swapped pages. */
-#define PAGE_SWAPPED         (1<<9) 
+#define PAGE_SWAPPED         (1<<9)
 #define PAGE_UNSWAPPED       (0)
 #define PAGE_WT              0x08   /* 00001000b : Write through */
 #define PAGE_CD              0x10   /* 00010000b : Cache disabled */
@@ -33,47 +35,40 @@
 #define va_to_pde(va)    ((va) >> 22)
 #define va_to_pte(va)    (((va) >> 12) & 0x3ff)
 
+typedef k_ui32_t page_entry_t; // for pd/pt declarations
+
 struct mm_context {
   paddr_t    pd;
   k_ui16_t   pd_index_in_pd_table;
   spinlock_t user_space_lock;
 };
 
-typedef struct mapping_s
+struct rmap
 {
   k_ui32_t index_team :10;
   k_ui32_t index_pde  :10;
   k_ui32_t index_pte  :10;
   k_ui32_t is_pt      :1;
   k_ui32_t unused     :1;
-  struct mapping_s *next;
-} mapping_t;
-
-struct rmap_session_s {
-  struct mapping_s* page_rmap;
-  struct mapping_s* pt_rmap;
+  struct rmap *next;
 };
 
-struct _rmap_ops_s {
-  int (*pre_add_rmapping)(struct rmap_session_s *rmap_session);
-  int (*do_add_rmapping)(struct rmap_session_s *rmap_session,
-			 k_ui32_t index_team, gpfme_t *gpfme, 
-			 vaddr_t virt, bool_t is_pt);
-  int (*post_add_rmapping)(struct rmap_session_s *rmap_session);
-  
-  int (*pre_del_rmapping)(struct rmap_session_s *rmap_session);
-  int (*do_del_rmapping)(struct rmap_session_s *rmap_session,
-			 k_ui32_t index_team, gpfme_t *gpfme, 
-			 vaddr_t virt);
-  int (*post_del_rmapping)(struct rmap_session_s *rmap_session);
+struct rmap_ops
+{
+  struct rmap * (*alloc)(void);
+  result_t      (*free) (struct rmap *r);
+  result_t      (*add)  (paddr_t paddr, struct rmap *r,
+			 int index_team, int index_pde, int index_pte, bool_t is_pt);
+  result_t      (*del)  (paddr_t paddr, int index_team, int index_pde,
+			 int index_pte, bool_t is_pt, struct rmap **result);
 };
-extern struct _rmap_ops_s _rmap_ops;
 
 /* Defined in _gdt.c */
 int _init_gdt(void);
 
 /* Defined in _team_mm_context.c */
 int _init_pd_table_mapper(void);
+result_t _sync_pd(int index_in_pd, page_entry_t pde);
 
 /* in _pgflt.c */
 cpu_state_t *_page_fault (int numirq,
@@ -82,10 +77,7 @@
 /* in _vmap.c */
 page_entry_t _get_pte_unsafe(vaddr_t virt);
 
-__init_text int _remap_init(void);
-
-__init_text int _rmap_init(kernel_parameter_t*);
-
-extern spinlock_t arch_remap_tmp_page;
+/* in _rmap.c */
+__init_text int _rmap_init(void);
 
 #endif

Index: Makefile
===================================================================
RCS file: /var/cvs/kos/kos/modules/x86/mm/Makefile,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- Makefile	8 Jul 2002 07:50:56 -0000	1.4
+++ Makefile	28 Dec 2004 18:45:02 -0000	1.5
@@ -1,8 +1,9 @@
-OBJS= _gdt.o _vmap.o _rmap.o _team_mm_context.o _pgflt.o mm.o
+OBJS= _gdt.o _vmap.o _team_mm_context.o _pgflt.o _rmap.o mm.o
+DEBUG_LEVEL=0
 
-all: arch-mm.ro
+all: arch_mm.ro
 
-arch-mm.ro: $(OBJS)
+arch_mm.ro: $(OBJS)
 
 TOPSRCDIR:=../../..
 include $(TOPSRCDIR)/modules/MkRules

Index: _team_mm_context.c
===================================================================
RCS file: /var/cvs/kos/kos/modules/x86/mm/_team_mm_context.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- _team_mm_context.c	27 Oct 2003 15:37:32 -0000	1.18
+++ _team_mm_context.c	28 Dec 2004 18:45:02 -0000	1.19
@@ -1,11 +1,38 @@
-/*
- * Copyright (C) 2000, Thomas PETAZZONI
- * http://kos.enix.org
+/** @file
+ * Architecture-dependant address space creation and destruction procedures
  *
+ * <b>General description</b>
  *
- * @(#) $Id$
+ * This file contains functions that allow to create and destroy
+ * address spaces. It mainly involves the allocation/free of the
+ * mm_context structure, the allocation/free of a PD for the new
+ * address space and the initialization of the new PD.
+ *
+ * <b>The PD table mapper mechanism</b>
+ *
+ * All address spaces have a kernel part (between 0 and
+ * USER_SPACE_START), in which the kernel space is mapped, and all of
+ * them must have the same view of this part of their address
+ * space. As each address space has its own page directory, we have to
+ * make sure that the part of these PDs that correspond to the kernel
+ * area must be coherent in all address spaces. In order to do this,
+ * the physical address of all PD's are stored in a special PT called
+ * the PD table mapper (this PT is at PD_TABLE_MAPPING_INDEX in all
+ * PD's) . Storing the physical addresses of all PD's makes them
+ * available in all address spaces, so that we can easily updates all
+ * of them.
+ *
+ * So when a new address space is created, a slot is allocated inside
+ * the PD table mapper, using the team_mm_contexts_bitmap. Then,
+ * during each mapping or unmapping of a PT inside the kernel space,
+ * the _sync_pd function is called to update all PD's.
+ *
+ * @author Thomas Petazzoni
+ * @author David Decotigny
  */
 
+/* @(#) $Id$  */
+
 #include <loader/mod.h>
 
 #include <debug/debug.h>
@@ -20,24 +47,41 @@
 
 #include "_mm.h"
 
-/*
- * For each team, pd[PD_TABLE_MAPPING_INDEX] = ptr to the PT containing
- * the addresses of all the PDs.
- */
+/** The PD table mapper is the PT of index PD_TABLE_MAPPING_INDEX in
+ *  all teams (see above for more explanations) */
 static page_entry_t *pd_table_mapper;
 
+/** The bitmap that allows to keep track of used and unused slots
+ *  inside the PD table mapper.
+ *
+ * @todo Maybe we could remove this bitmap, and directly used the
+ * pd_table_mapper to keep track of used and unused slots : any slot
+ * that contains 0 is free, any other slot is used.
+ */
 static k_ui32_t team_mm_contexts_bitmap[ALIGN_SUP(MAX_TEAM_NUMBER, NBITS(k_ui32_t))/NBITS(k_ui32_t)];
 
-/* A mm_context for the very first team (because we don't have any
-   kmalloc() yet) */
+/** The mm_context for the very first team (because we don't have any
+ *  kmalloc() yet) */
 static struct mm_context primary_team_mm_ctxt;
 
-/* Task address space allocator. It does not just allocate a physical
-   page for the PD of the task, but also write the address of the PD
-   in a special PT, so as the PD to be accessible for the kernel. This
-   is necessary in order to avoid context switch when maintaining
-   kernel space coherency */
-
+/** Builds a new address space for a new team
+ *
+ * This function builds a new address space for a new team. This
+ * involves :
+ *  - The allocation of a slot in the PD table mapper
+ *  - Allocation of the struct mm_context structure
+ *  - Allocation of a physical page for the PD
+ *  - Registration of the newly allocated PD in the PD table mapper
+ *    mechanism
+ *  - Initialization of the kernel part of the PD by copying the kernel
+ *    part of the current address space PD.
+ *
+ * @param out_mm_ctxt Indicates where the address of the new struct
+ *                    mm_context, representing the new address space
+ *                    should be returned.
+ *
+ * @result ESUCCESS on success, an error code otherwise
+ */
 result_t arch_team_mm_context_construct(struct mm_context ** out_mm_ctxt)
 {
   unsigned int index;
@@ -45,19 +89,22 @@
   page_entry_t *pd;
   struct mm_context *mm_ctxt;
 
+  /* Find a empty slot in the PD table mapper */
   write_spin_lock(kernel_team_pd_bitmap_lock, flags);
   index =  bsf_bitmap((vaddr_t) team_mm_contexts_bitmap,
 		      sizeof(team_mm_contexts_bitmap));
   if(index >= NBITS(team_mm_contexts_bitmap))
     {
       write_spin_unlock(kernel_team_pd_bitmap_lock, flags);
-      return -1;
+      return -ENOMEM;
     }
 
   /* Mark this slot as used in the bitmap */
   set_bit_in_bitmap((vaddr_t) team_mm_contexts_bitmap, index, 0);
   write_spin_unlock(kernel_team_pd_bitmap_lock, flags);
-  
+
+  /* Allocates an initializes the mm_context structure, and take care
+     of the special case of the very first team */
   if (index == PRIMARY_TEAM_PD_ID)
     {
       mm_ctxt = & primary_team_mm_ctxt;
@@ -79,37 +126,40 @@
       memset(mm_ctxt, 0, sizeof(struct mm_context));
 
       /* Allocate new PD for the team */
-      mm_ctxt->pd = get_physical_page(PHYS_PAGE_KERNEL, 
-				      PHYS_PAGE_NON_SWAPPABLE);
-      __dbg_printk("Physical page allocated for this PD is 0x%x\n", 
+      mm_ctxt->pd = physmem_get_page(PHYS_PAGE_KERNEL,
+				     PHYS_PAGE_NON_SWAPPABLE);
+      DEBUG_PRINT2("[arch_team_mm_context_construct] Physical page allocated for this PD is 0x%x\n",
 		   mm_ctxt->pd);
-  
+
       if(mm_ctxt->pd == 0)
 	return -ENOMEM;
     }
 
-  /* Insert the address of the PD in the correct slot of the list,
-     making this PD available in all teams at
-     PD_TABLE_MAPPING_START+index*PAGE_SIZE == pd */
+  /* Register the newly allocated PD in the PD table mapper mechanism
+   * by inserting the PD address in the correct slot of the PD
+   * array. This will allow all teams to access to this PD at address
+   * PD_TABLE_MAPPING_START + index * PAGE_SIZE */
   mm_ctxt->pd_index_in_pd_table = index;
   pd_table_mapper[index]  = (page_entry_t) mm_ctxt->pd;
   pd_table_mapper[index] |= (PAGE_SUPERVISOR | PAGE_RW | PAGE_PRESENT);
 
+  DEBUG_PRINT2("[arch_team_mm_context_construct] Assigning %d as PD INDEX\n", mm_ctxt->pd_index_in_pd_table);
+
   if (index != PRIMARY_TEAM_PD_ID)
     {
-      memset((char *) (PD_TABLE_MAPPING_START + index*PAGE_SIZE), 
+      memset((char *) (PD_TABLE_MAPPING_START + index*PAGE_SIZE),
 	     0, PAGE_SIZE);
 
       /* Copy the contents of kernel team 0 PD into newly created team's PD */
       memcpy((char *) (PD_TABLE_MAPPING_START + index*PAGE_SIZE),
 	     (char *) (PD_TABLE_MAPPING_START + PRIMARY_TEAM_PD_ID*PAGE_SIZE),
 	     KERNEL_MEMORY_NUMBER_OF_PT * sizeof(k_ui32_t));
-      
+
       /* Enable mirroring on the new PD. This MUST be done in order to
-	 always have the PD of the current team mapped at the same
-	 (CURRENT_PT_AREA_INDEX) PDE.
-	 This MUST be done AFTER the memcpy above to avoid having same
-	 mirroring as kernel team 0.
+       * always have the PD of the current team mapped at the same
+       * (CURRENT_PT_AREA_INDEX) PDE.
+       * This MUST be done AFTER the memcpy above to avoid having same
+       * mirroring as kernel team 0.
       */
       pd = (page_entry_t *) (PD_TABLE_MAPPING_START + index*PAGE_SIZE);
       pd[CURRENT_PT_AREA_INDEX] = (page_entry_t) (mm_ctxt->pd);
@@ -122,8 +172,17 @@
   return ESUCCESS;
 }
 
-
-int arch_team_mm_context_destruct(struct mm_context * mm_ctxt)
+/** Deletes an memory context (an address space)
+ *
+ * This function deletes the given address space by releasing the slot
+ * in the team_mm_contexts_bitmap, removing the PD from the
+ * pd_table_mapper and freeing the PD itself.
+ *
+ * @param mm_ctxt The memory context that has to be freed
+ *
+ * @return ESUCCESS (always successful)
+ */
+result_t arch_team_mm_context_destruct(struct mm_context * mm_ctxt)
 {
   int index;
   paddr_t pd;
@@ -151,19 +210,91 @@
   write_spin_unlock(kernel_team_pd_bitmap_lock, flags);
 
   /* We do this outside spinlock */
-  put_physical_page(pd);
+  physmem_put_page(pd);
 
-  return 0;
+  /* Free the memory context */
+  kfree(mm_ctxt);
+
+  return ESUCCESS;
 }
 
-result_t arch_team_mm_context_switch(struct mm_context *mm_ctxt)
+/** Synchronize the kernel part of all PDs.
+ *
+ * Scan the pd_table_mapper table, and for each entry corresponding to
+ * a present PD, updates the correct PDE entry to ensure that all
+ * address spaces will share the same view of the kernel space (see
+ * top of the file for more explanations)
+ *
+ * @param index_in_pd The index of the PDE that has been changed
+ * inside the PD.
+ *
+ * @param pde The PDE itself
+ *
+ * @result ESUCCESS (always successful)
+ *
+ * @note There's no need to take any lock during this function. If it
+ * gets called, it's because a page is being mapped or unmapped from
+ * the kernel space. So the kernel space lock is already held, and we
+ * don't need to take any other lock.
+ */
+result_t _sync_pd(int index_in_pd, page_entry_t pde)
+{
+  int i;
+
+  DEBUG_PRINT3("Synchronize all address spaces\n");
+
+  /* During the initialization of the system, no need to synchronize
+     address spaces : there's only one ! Moreover, the PD table mapper
+     is not initialized at the very first stages of the
+     initialization. */
+  if(get_current_thread() == NULL)
+    return ESUCCESS;
+
+  /* Go through each entry (yes, this is very suboptimal) */
+  for (i = 0; i < MAX_TEAM_NUMBER ; i++)
+    {
+      /* If there's an associated PD, we must update it */
+      if(IS_PRESENT(pd_table_mapper[i]))
+	{
+	  page_entry_t *pd;
+
+	  /* Compute the PD virtual address */
+	  pd = (page_entry_t *) (PD_TABLE_MAPPING_START + i * PAGE_SIZE);
+
+	  /* Update the entry */
+	  pd[index_in_pd] = pde;
+	}
+    }
+
+  return ESUCCESS;
+}
+
+/** Switch to an other memory context
+ *
+ * This functions switches to an other memory context (an other
+ * address space) by changing the address of the current PD. On an x86
+ * platform, this is done by changing the value in the <i>cr3</i>
+ * register, which contains the <i>physical</i> address of the PD.
+ *
+ * @param mm_ctxt The address space we want to switch to
+ *
+ * @return ESUCCESS (always successful)
+ */
+result_t arch_team_mm_context_switch(const struct mm_context *mm_ctxt)
 {
   asm volatile("movl %0,%%cr3"::"r"(mm_ctxt->pd));
 
   return ESUCCESS;
 }
 
-__init_text int _init_pd_table_mapper(void)
+/** Initialize the PD Table mapper
+ *
+ * This function is called during the initialization to build the PD
+ * table mapper mechanism.
+ *
+ * @result ESUCCESS (always successful)
+ */
+__init_text result_t _init_pd_table_mapper(void)
 {
   paddr_t *pd = (page_entry_t*) CURRENT_PD_VADDR;
   paddr_t ppage;
@@ -175,7 +306,7 @@
 
   /* Allocate page for the new PT, which will be used to maintain the
      list of the addresses of all PDs of all teams */
-  ppage = get_physical_page(PHYS_PAGE_KERNEL, PHYS_PAGE_NON_SWAPPABLE);
+  ppage = physmem_get_page(PHYS_PAGE_KERNEL, PHYS_PAGE_NON_SWAPPABLE);
   CONCEPTION_ASSERT(ppage != 0);
 
   /* Make this PT available */
@@ -185,5 +316,5 @@
 				      + PD_TABLE_MAPPING_INDEX*PAGE_SIZE);
   memset((void *) pd_table_mapper, 0, PAGE_SIZE);
 
-  return 0;
+  return ESUCCESS;
 }

Index: mm.c
===================================================================
RCS file: /var/cvs/kos/kos/modules/x86/mm/mm.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- mm.c	27 Oct 2003 15:37:32 -0000	1.14
+++ mm.c	28 Dec 2004 18:45:02 -0000	1.15
@@ -37,6 +37,7 @@
     return 1;
   printk("] ");
 
+  /*
   printk("[remap init");
   if(_remap_init() != 0)
     return -1;
@@ -46,31 +47,49 @@
   if(_rmap_init(kp))
     return -1;
   printk("] ");
+  */
 
   printk("Ok)\n");
 
   return 0;
 }
 
+__init_text static int init_module_level2(kernel_parameter_t *kp)
+{
+  UNUSED(kp);
+
+  printk("[rmap");
+  if(_rmap_init())
+    return -1;
+  printk("] ");
+
+  return 0;
+}
+
 __init_text static int post_init_module_level0(kernel_parameter_t *kp)
 {
   UNUSED(kp);
-  
+
   return 0;
 }
 
 DECLARE_INIT_SYMBOL(init_module_level1, INIT_LEVEL1);
+DECLARE_INIT_SYMBOL(init_module_level2, INIT_LEVEL2);
 DECLARE_INIT_SYMBOL(post_init_module_level0, POST_INIT_LEVEL0);
 
-EXPORT_FUNCTION(arch_map_virtual_page);
-EXPORT_FUNCTION(arch_init_gdt_tss_entry);
-EXPORT_FUNCTION(arch_dump_gdt);
-EXPORT_FUNCTION(arch_get_paddr_at_vaddr);
-EXPORT_FUNCTION(arch_unmap_virtual_page);
-EXPORT_FUNCTION(arch_get_vpage_status);
-EXPORT_FUNCTION(arch_team_mm_context_construct);
-EXPORT_FUNCTION(arch_team_mm_context_destruct);
-EXPORT_FUNCTION(arch_remap_virtual_page);
-EXPORT_FUNCTION(arch_protect_virtual_page);
-EXPORT_FUNCTION(arch_team_mm_context_switch);
-EXPORT_FUNCTION(arch_range_dup);
+EXPORT_FUNCTION_RESTRICTED(arch_pre_map_virtual_page,      vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_do_map_virtual_page,       vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_post_map_virtual_page,     vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_pre_unmap_virtual_page,    vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_do_unmap_virtual_page,     vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_post_unmap_virtual_page,   vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_get_virtual_page_status,   vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_get_paddr_at_vaddr,        vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_protect_virtual_page,      vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_team_mm_context_construct, vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_team_mm_context_destruct,  vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_team_mm_context_switch,    vmm);
+EXPORT_FUNCTION_RESTRICTED(arch_init_gdt_tss_entry,        arch_task);
+#if (DEBUG_LEVEL > 2)
+EXPORT_FUNCTION(arch_rmap_list_display);
+#endif

Index: mm.h
===================================================================
RCS file: /var/cvs/kos/kos/modules/x86/mm/mm.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- mm.h	27 Oct 2003 15:37:32 -0000	1.14
+++ mm.h	28 Dec 2004 18:45:02 -0000	1.15
@@ -25,59 +25,64 @@
 #define PAGE_ALIGN_INF(addr) \
   ALIGN_INF((addr), PAGE_SIZE)
 
-typedef enum { 
-  VM_ACCESS_READ  = 0x1, 
-  VM_ACCESS_WRITE = 0x2, 
+/** @todo Change the name to be consistent with vpage_status_t */
+typedef enum {
+  VM_ACCESS_READ  = 0x1,
+  VM_ACCESS_WRITE = 0x2,
   VM_ACCESS_EXEC  = 0x4
 } access_right_t;
 
-/* TODO : move this typedef to _mm.h */
-typedef k_ui32_t page_entry_t; // for pd/pt declarations
+typedef enum {
+  PHYS_PAGE_PRESENT,
+  PHYS_PAGE_SWAPPED,
+  PHYS_PAGE_UNMAPPED
+} vpage_status_t;
 
 struct mm_context;
 
-/* vpage AND ppage MUST be page-aligned. When dest_mm_ctxt is NULL,
-   then always map in the current team. Function must always be
-   operational, even when rmap is not yet initalised. */
-result_t arch_map_virtual_page(struct mm_context * dest_mm_ctxt,
-			       vaddr_t vpage, paddr_t ppage,
-			       access_right_t access_rights);
-
-/* Change the flags for the (mapped) vpage */
-result_t arch_protect_virtual_page(struct mm_context * dest_mm_ctxt,
-				   vaddr_t vpage,
-				   access_right_t access_rights);
-
-/* vpage AND new_ppage MUST be page-aligned. When dest_mm_ctxt is
-   NULL, then always remap in the current team. vpage is unmapped from
-   previous physical address, and remapped at new_ppage. The vpage may
-   be the page of the current stack, or of the current IP. */
-result_t arch_remap_virtual_page(struct mm_context * dest_mm_ctxt,
-				 vaddr_t vpage, paddr_t new_ppage);
-
-/* vpage MUST be page-aligned. When dest_mm_ctxt is NULL, then always
-   unmap in the current team. */
-result_t arch_unmap_virtual_page(struct mm_context * dest_mm_ctxt,
-				 vaddr_t vpage);
-
-/* switch to an other mm_context */
-result_t arch_team_mm_context_switch(struct mm_context *mm_ctxt);
+/** This structure contains all informations during a virtual mapping
+    or unmapping session */
+struct map_session
+{
+  /* The reverse mapping structure for the page being mapped or
+     unmapped */
+  struct rmap *page_rmap;
 
-result_t arch_range_dup(struct mm_context *to,
-			vaddr_t start, vaddr_t end, access_right_t ar);
+  /* The reverse mapping structure for the PT being mapped or
+     unmapped, if any */
+  struct rmap *pt_rmap;
 
-typedef enum { PHYS_PAGE_PRESENT,
-	       PHYS_PAGE_SWAPPED,
-	       PHYS_PAGE_UNMAPPED } vpage_status_t;
-vpage_status_t arch_get_vpage_status(struct mm_context * dest_mm_ctxt,
-				     vaddr_t vaddr);
+  /* The physical address of the PT to be mapped or unmapped, if
+     any */
+  paddr_t pt_paddr;
+};
 
-paddr_t arch_get_paddr_at_vaddr(vaddr_t vaddr);
+/* Defined in _vmap.c */
+result_t arch_pre_map_virtual_page(struct map_session *map_session);
+result_t arch_do_map_virtual_page(struct map_session *map_session,
+				  const struct mm_context * dest_mm_ctxt,
+				  paddr_t paddr, vaddr_t vaddr,
+				  access_right_t access_rights);
+result_t arch_post_map_virtual_page(struct map_session *map_session);
 
-/* Team address space management: for VMM use */
-struct team;
+result_t arch_pre_unmap_virtual_page(struct map_session *map_session);
+result_t arch_do_unmap_virtual_page(struct map_session *map_session,
+				    const struct mm_context *dest_mm_ctxt,
+				    vaddr_t vaddr);
+result_t arch_post_unmap_virtual_page(struct map_session *map_session);
+result_t arch_get_paddr_at_vaddr(const struct mm_context * dest_mm_ctxt,
+				 vaddr_t vaddr, paddr_t *paddr);
+result_t arch_get_virtual_page_status(const struct mm_context * dest_mm_ctxt,
+				      vaddr_t vaddr, vpage_status_t *status);
+result_t arch_protect_virtual_page(const struct mm_context *dest_mm_ctxt,
+				   vaddr_t vaddr, access_right_t access_rights);
 result_t arch_team_mm_context_construct(struct mm_context ** out_mm_ctxt);
 result_t arch_team_mm_context_destruct(struct mm_context * mm_ctxt);
+result_t arch_team_mm_context_switch(const struct mm_context *mm_ctxt);
+
+#if (DEBUG_LEVEL > 2)
+result_t arch_rmap_list_display(paddr_t paddr);
+#endif
 
 struct tss;
 int arch_init_gdt_tss_entry(int seg_sel, struct tss *tss);

Index: _vmap.c
===================================================================
RCS file: /var/cvs/kos/kos/modules/x86/mm/_vmap.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- _vmap.c	27 Oct 2003 15:37:32 -0000	1.26
+++ _vmap.c	28 Dec 2004 18:45:02 -0000	1.27
@@ -1,44 +1,125 @@
-/*
- * Copyright (C) 2000, Thomas PETAZZONI
- * http://kos.enix.org
+/** @file
+ * Architecture-dependant mapping and unmapping procedures
+ *
+ * @author Thomas Petazzoni, David Decotigny, Julien Munier
+ *
+ * <b>Locking considerations</b>
+ *
+ * The mapping and unmapping process has been split into three steps
[...1421 lines suppressed...]
-  pd = (page_entry_t*)CURRENT_PD_VADDR;
-  pt = (page_entry_t*)(CURRENT_PT_AREA_START + va_to_pde(tmp_map_addr)*PAGE_SIZE);
+  /* Change access rights */
+  pt[va_to_pte(vaddr)] =
+    (pt[va_to_pte(vaddr)] & (~PAGE_RW)) |
+    (_translate_access_rights(vaddr, access_rights) & (PAGE_RW));
 
-  if(IS_UNMAPPED(pd[va_to_pde(tmp_map_addr)]))
-    {
-      paddr = get_physical_page(PHYS_PAGE_KERNEL, PHYS_PAGE_NON_SWAPPABLE);
-      pd[va_to_pde(tmp_map_addr)] = _translate_vm_entry(paddr, PAGE_SUPERVISOR | PAGE_RW | PAGE_PRESENT);
-    }
+  /* TODO: Do only if the page is in the current address space */
+  invlpg(vaddr);
 
-  spinlock_init(arch_remap_tmp_page);
-  
-  return 0;
+  return ESUCCESS;
 }



More information about the Kos-cvs mailing list