home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / mach / doc / notes / pmap-notes.Z / pmap-notes
Encoding:
Internet Message Format  |  1993-04-05  |  27.7 KB

  1. Subject: Pmap specifications and implementation hints
  2. Author:    Bob Wheeler (who wrote it under duress)
  3. Date:    Apr. 22, 1992
  4. --------------------------------------------------------
  5. Subject: Mach porting notes available, these are
  6.     in additions to the notes in this file.
  7. Date: Tue, 23 Mar 93 12:03:05 EST
  8.  
  9. Bob Wheeler has made available his slides for his Symposium
  10. on "Porting and Modifying the Mach 3.0 Microkernel" at the Third
  11. USENIX Mach Symposium, April 19, 1993
  12.  
  13. The 3 hour symposium will touch on all the parts of the Mach 3.0 kernel
  14. that need to be changed for a new machine type. As a result it needs to
  15. cover the internals of the virtual memory system, external pager, context
  16. switches, continuations, cthreads implementation and emulated system
  17. calls.
  18.  
  19. These slides are a good roadmap to reading and understanding the source
  20. code or may be an enticement for you to attend the symposium if you really
  21. want to learn about the internals of Mach 3.0.
  22.  
  23. They are available by FTP from mach.cs.cmu.edu, as user anonymous, in file
  24. doc/unpublished/porting.tutorial.slides.ps{.Z}
  25.  
  26.                 Mary Thompson
  27.  
  28. ---------------------------------------------------------
  29. N.B. This is a first draft of a pmap implementation guide and
  30. should be read with the following cautionary note in mind.
  31.  
  32.   CARNEGIE MELLON ALLOWS FREE USE OF THIS DOCUMENT IN ITS "AS IS"
  33.   CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  34.   ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS DOCUMENT.
  35. ---------------------------------------------------------------
  36.  
  37. A pmap or "physical map" is just a data structure that keeps track of 
  38. translations and protections for virtual to physical pages. Some machines
  39. have hardware restrictions on what the data structure is. The vax, m68030
  40. and i80386 all force the data structure to be a "page table". The R6000 
  41. uses an "inverted page table" while the PA-RISC and Mips chips are "software
  42. loaded tlbs" and you can do anything you want from page tables to linked
  43. lists, binary search trees or hash tables. The important point is that the
  44. machine-independent form doesn't care what you use to represent these
  45. translations. More likely than not your hardware will dictate the format
  46. of your data structure. There is one pmap per address space. Which in
  47. Mach means one for the kernel address space and one for each task. When
  48. a thread is being activated, the pmap module is called to load up the
  49. hardware with whatever register values or TLB contents the processor will
  50. need to reference the address space of the task to which the thread belongs.
  51.  
  52. Whatever your data structure is it must be able to do the following 
  53. operations:
  54.  
  55.     insert new virtual to physical translations
  56.     remove a virtual to physical translation
  57.     lookup a virtual to physical translation
  58.     change protection on a virtual to physical translation
  59.     remove all translations to a physical page
  60.     change the protection on all translations to a physical page
  61.     keep track of whether a physical page has been written on
  62.     keep track of whether a physical page has been referenced
  63.  
  64. One thing to notice is that you need to be able to find a translation given
  65. either the physical or the virtual address. This means that even if you 
  66. use a forward page table for virtual to physical translations you will 
  67. need to have a way to find all mappings to a physical page. In addition 
  68. some things like "Is the page dirty?" apply to the physical page, not 
  69. to a translation (even though the hardware typically reports the page that 
  70. was written on by giving the virtual address).
  71.  
  72. The upshot is that you typically keep an array around and an entry in the array
  73. corresponds to a physical page. The array holds the dirty bit for the page, 
  74. it may hold the reference bit for the page and it probably holds a pointer
  75. to some linked list which tells the virtual addresses that map to that page.
  76.  
  77. You define a pmap structure which is really just a handle to whatever 
  78. your data structure is. Some pmap modules contain a pointer to a page table
  79. structure, others just contain a "process ID". You usually don't put the 
  80. page table in the pmap structure, you just put a hook (a pointer) to the
  81. table or data structure. Usually the pmap structure will have the form:
  82.  
  83.     typedef struct pmap {
  84.             simple_lock_data_t      lock;        /* lock on pmap */
  85.             int                     ref_count;   /* reference count */
  86.             struct pmap_statistics  stats;       /* statistics */
  87.             struct pmap             *next;       /* list for free pmaps */
  88.         /*
  89.          * a pointer to your data structure or whatever else you need.
  90.          */
  91.     } *pmap_t;
  92.  
  93. The lock is so that we can control access to the pmap in a multi-processor
  94. environment (you really don't need it if you only have a uni-processor.) The 
  95. reference count will be used to determine when we can remove a particular pmap
  96. structure. pmap_statistics contains statistics that are kept by your pmap 
  97. routines and they are used to report memory usage. The next pointer is used to
  98.  link pmap structures that are not used into a free pmap list.
  99. Because we might have multiple things in the kernel wanting access to a pmap,
  100. we need a way to tell when everyone is done with a map. The way we do this is 
  101. with a reference count. 
  102.  
  103. You need to define a pmap for the kernel's address space and define
  104. a global pointer to it called kernel_pmap.
  105.  
  106.     struct pmap kernel_pmap_store;
  107.     pmap_t kernel_pmap = &kernel_pmap_store;
  108.  
  109. Basically, anytime the pmap routines are called with a  virtual address, 
  110. the caller will also provide a pointer to the pmap structure for the 
  111. address space in which the virtual address resides.
  112.  
  113. Here are the routines that you need to write:
  114.  
  115. ROUTINES USED ONLY AT BOOTSTRAP TIME...
  116.  
  117. There is a routine that is called before virtual memory is turned on that
  118. initializes all the data structures, does whatever is needed to make sure the 
  119. kernel is mapped and sets up all the VM data structures. Traditionally this
  120. routine is called pmap_bootstrap. It is only called by machine dependent code
  121. and thus you really don't have to have a pmap_bootstrap and there are no real 
  122. "defined" arguments for it, but you should call it pmap_bootstrap just so that
  123. the next person knows where to look for the routine. It is usually called after
  124. the bus and memory have been configured. This routine should also set the 
  125. reference count on the kernel's pmap to 1.
  126.  
  127. One of the things that pmap_bootstrap does is map the kernel. The routine 
  128. that is typically used to map the kernel is called pmap_map(). This routine 
  129. is only called by the machine dependent routine pmap_bootstrap. The machine
  130. independent code knows nothing about it. The real difference between it and
  131. pmap_enter() (besides the fact that it is only called at boot time), is that 
  132. it maps a range of address space and it always maps it into the kernel's 
  133. pmap.
  134.  
  135. /*
  136.  *      Initialize the kernel's physical map.
  137.  *
  138.  *      This routine could be called at boot.  It maps a range of
  139.  *      physical addresses into the kernel's virtual address space.
  140.  *
  141.  */
  142. vm_offset_t pmap_map(virt, start, end, prot)
  143.         vm_offset_t     virt;           /* Starting virtual address.    */
  144.         vm_offset_t     start;          /* Starting physical address.   */
  145.         vm_offset_t     end;            /* Ending physical address.     */
  146.         int             prot;           /* Machine indep. protection.   */
  147.  
  148. Now we have to talk about a few special values that are set up at bootstrap
  149. time. These values are not referenced by the machine independent code, 
  150. but you should use these names so that we all know what you're talking 
  151. about.
  152.  
  153.     extern vm_offset_t avail_start, avail_end;
  154.  
  155. This is the address range (all addresses in Mach are in bytes), of the 
  156. physical memory that the VM system should manage. It defines memory
  157. as any address p such that avail_start <= p < avail_end.
  158.  
  159. All address ranges in Mach work this way, the lower address is included in
  160. the range of addresses but the upper address is not included.
  161.  
  162.     extern vm_offset_t virtual_avail, virtual_end;
  163.  
  164. This is the address range that Mach should allocate kernel virtual memory 
  165. from.
  166.  
  167. Here's what the deal is. The kernel is in memory and the text, data and bss
  168. of the kernel are not paged. There are also probably page tables, and other
  169. data items that are sized at boot time that must always stay resident.
  170.  
  171. In pmap_bootstrap, you use pmap_map() to map all this text and data into the
  172. kernel map. Now since it's not going anywhere, it's always "resident" we
  173. really don't want or need the VM system manageing it. So one normally
  174. sets avail_start to the first physical page past all this resident text and
  175. data and avail_end to the first word that is not in physical memory.
  176. Then we usually set virtual_avail to be the first virtual address that we
  177. want to use that is not already mapped in the kernel and virtual_end to the 
  178. end of this range. 
  179.  
  180. Now when you are boot strapping, you will probably carve out hunks of physical
  181. memory for your data structures that must be resident. The machine independent
  182. (MI) code also has data structures that need to be resident. The MI code needs
  183. a way to grab physical pages of memory for allocation at bootstrap time. 
  184. For example, every physical page of memory managed by the VM system has a 
  185. struture called vm_page (see vm/vm_page.h) that descibes the physical page.
  186. This tells us if the page is in transit from a pager, it's allocated, busy,
  187. on the free list and so forth. The kernel needs to allocate one of these per
  188. physical page. Sice these structures can't be pages and will never move
  189. once their allocated in physical memory, why have the VM system manage them?.
  190. Instead the MI code cuts out "resident" memory for them at boot time.
  191.  
  192. Now, there are two ways to let the VM system get resident memory.
  193. If you define the CPP macro MACHINE_PAGES in your pmap.h file, then this means
  194. that the pmap wants control of all allocation for the kernel. This flexability
  195. is included for ports that really want to do strange things at bootstrap
  196. time for various reasons. The PA-RISC port and the Mips port are two such 
  197. animals.
  198.  
  199. If you don't define MACHINE_PAGES then here are the routines you must write:
  200.  
  201.     pmap_free_pages : This returns the number of free physical pages
  202.     left in memory. Basically it's the following routine:
  203.  
  204.         unsigned int pmap_free_pages()
  205.         {
  206.             return atop(avail_end - avail_start);
  207.         }
  208.  
  209.     where atop() takes bytes and converts them to pages (shifts right
  210.     some number of bits).
  211.  
  212.     pmap_virtual_space - just return the start and ending virtual 
  213.     addresses. This is needed because the MI code doesn't really know about
  214.     virtual_avail and virtual_end and this is how it finds the range of 
  215.     virtual addresses that it can allocate for the kernel. It's easy:
  216.  
  217.         void pmap_virtual_space(startp, endp)
  218.                 vm_offset_t *startp;
  219.                 vm_offset_t *endp;
  220.         {
  221.                 *startp = virtual_avail;
  222.                 *endp = virtual_end;
  223.         }
  224.  
  225.     pmap_next_page - return the address of the next physical page that is 
  226.     available. It returns the address (in bytes) of the physical page 
  227.     through the pointer addrp. It returns TRUE (defined in mach/boolean.h)
  228.     if there was a page to allocate and FALSE if there wasn't. It's 
  229.     basically:
  230.  
  231.         boolean_t pmap_next_page(addrp)
  232.                 vm_offset_t *addrp;
  233.         {
  234.                 if (avail_next == avail_end)
  235.                         return FALSE;
  236.     
  237.                 *addrp = avail_next;
  238.                 avail_next += PAGE_SIZE;
  239.                 return TRUE;
  240.         }    
  241.  
  242.     pmap_init - called after kernel is running in virtual memory and all 
  243.     resident data structures have been allocated. You can call zinit() to 
  244.     allocate zones even though zone_init() has not been called.
  245.  
  246.     This is where you can set up zones for allocating new pmaps, new page
  247.     tables or just do general housekeeping that needs to be done for 
  248.     your pmap module. You don't have to do anything here if you don't 
  249.     need to. It's just a hook to let you set up anything that you need to
  250.     after we are running in virtual memory but before we really start 
  251.     running the kernel. The function returns void and there are no
  252.     arguments.
  253.  
  254. Here's what the kernel is going to do. It will first call your routine
  255. pmap_virtual_space() to get a range of kernel virtual addresses that it can 
  256. use to allocate memory from. It has a routine called pmap_steal_memory() that 
  257. will call your pmap_next_page() to grab physical pages of memory for mapping
  258. all sorts of resident data structures needed by the kernel. As it grabs 
  259. physical pages it will call pmap_enter to enter the virtual address for the
  260. physical page into the kernel's address space. 
  261.  
  262. After all the resident memory is allocated that the MI code needs, it will
  263. repeatedly call pmap_next_page(), getting a physical page. It will take this
  264. page and fill in the vm_page structure for it and then add the page to the 
  265. free list. It keeps doing this until pmap_next_page() returns FALSE or 
  266. until it's allocated all the pages that pmap_free_pages() returned.
  267.  
  268. After it does it's own VM initialization, it will call your routine pmap_init()
  269. to let you do anything you need to in the pmap module.
  270.  
  271. Now, if you really want to get fancy and there is some *big* reason you really
  272. want control over allocation, you can define MACHINE_PAGES in your pmap.h
  273. and then you have to write the following four routines:
  274.  
  275.     pmap_free_pages - same as above
  276.     pmap_init - same as above
  277.  
  278.     pmap_steal_memory - grab "size" bytes of physical memory, do whatever 
  279.     you need to to get a virtual address mapped to it and return the 
  280.     virtual address for that memory.
  281.  
  282.         vm_offset_t pmap_steal_memory(size)
  283.                     vm_size_t size;
  284.  
  285.     pmap_startup - allocate a vm_page structure for every physical page, 
  286.     initialize the structure and put the physical page on the free list.
  287.     Return the starting and ending virtual addresses that the rest of the 
  288.     kernel can use to allocate kernel memory from.
  289.  
  290.         void pmap_startup(startp, endp)
  291.                 vm_offset_t *startp, *endp;
  292.  
  293. Ok, enough about resident pages. If you want to know more look at the comments
  294. in vm/pmap.h and the code in vm/vm_resident.c.
  295.  
  296. Until now we've only been talking about routines used to bootstrap the system,
  297. once we're up and running we will no longer use any of the routines described
  298. above.
  299.  
  300. ROUTINES USED AFER STARTUP
  301.  
  302. Here are the remaining pmap routines that you need to implement:
  303.  
  304. Define PMAP_NULL in your pmap.h file as 
  305.  
  306.     #define PMAP_NULL ((pmap_t)0)
  307.  
  308. We should start out with how you get a pmap for a new task, pmap_create().
  309.  
  310.     pmap_t pmap_create(size)
  311.             vm_size_t       size;
  312.  
  313. You should do whatever you have to to get a new pmap, perhaps allocate page
  314. tables or whatever, then set the reference count to 1 and return the pointer 
  315. to the pmap. Usually one 
  316. sets up a zone of pmaps in pmap_init() and you keep a linked list of free 
  317. pmaps that have been allocated, used and freed. You try and allocate one of 
  318. the free list. If that fails you get one from the zone. Then you do whatever
  319. local magic is needed to get it set up and you return it.
  320.  
  321. Here is the weird part. If the size is zero then this is a "real" physical 
  322. map and you need to allocate space for it. If the size is not zero then
  323. it is a "software only" map and you need not allocate real space for it. 
  324.  
  325. The bottom line is that it is never called with anything but 0. You probably 
  326. want to add a check like this at the top of the file
  327.  
  328.     if (size != (vm_size_t)0)
  329.         return PMAP_NULL;
  330.  
  331. just in case someday someone decides to reuse this fine feature.
  332.  
  333. The routine pmap_reference should just increment a 
  334. counter associated with the pmap. The routine should be:
  335.  
  336.     void pmap_reference(pmap)
  337.             pmap_t  pmap;
  338.     {
  339.             if (pmap != PMAP_NULL)
  340.                     map->ref_count++;
  341.     }
  342.  
  343. Again, this is so simple you probably want to define it as a macro, say...
  344.  
  345. #define pmap_reference(pmap) \
  346.     do { \
  347.         pmap->ref_count++; \
  348.     } while(0)
  349.  
  350. XXX - fix pmap.h so that this can be a macro
  351.  
  352.  
  353. The next obvious routine to talk about is pmap_destroy().
  354.  
  355.     void pmap_destroy(pmap)
  356.             pmap_t  pmap;
  357.  
  358. Decrement the reference count on the pmap, if it is not zero then just return.
  359. This routine will only be called after all mappings have been removed from the
  360. pmap using pmap_remove(). All you have to do is whatever cleanup you need to,
  361. (maybe free up some page tables or whatever) and then you will probably put 
  362. the pmap on a free list so that it can be reused by pmap_create().
  363.  
  364. The next routine pmap_kernel is really easy, just return the address of the
  365. kernel's pmap. Your routine will probably look like this:
  366.  
  367.     pmap_t pmap_kernel()
  368.     {
  369.             return (kernel_pmap);
  370.     }
  371.  
  372. Since this is such a trivial function, why do a function call. A better idea
  373. for this one is to put
  374.  
  375.     #define pmap_kernel() (kernel_pmap)
  376.  
  377. in your pmap.h file. 
  378.  
  379. XXX - Actually this is really stupid, most of the MI code just uses 
  380. kernel_pmap. It's only used in kmem_init in vm_kern.c. We should change this 
  381. to a pmap_kernel and get rid of this call altogether.
  382.  
  383. There is a set of macros that you need to define that activate and deactivate
  384. a pmap. The CPP macros that should be in your pmap.h file are:
  385.  
  386.     PMAP_ACTIVATE(pmap, thread, cpu)
  387.     PMAP_DEACTIVATE(pmap, thread, cpu)
  388.  
  389.     The arguments are 
  390.  
  391.         pmap_t pmap;        /* pointer to the pmap */
  392.         thread_t thread;    /* pointer to the thread */
  393.         int cpu;        /* the cpu to use */
  394.  
  395. Basically these macros should do whatever they need to in order to activate
  396. or deactivate a pmap on a machine. They are called with both the kernel's
  397. pmap and with user's pmap. They are used at context switch time, startup and 
  398. shutdown. Say you have page tables, these routines might change the value 
  399. of a root page table pointer for example. If you don't need them (for instance
  400. you have an inverted page table), just define them to be empty macros in 
  401. your pmap.h file.  They are implemented as macros for both efficiency
  402. and as a way to let them be null statements on machines where they are
  403. not needed.
  404.  
  405. If you need to split kernel and user pmap activations then you can define the
  406. following routines instead of the ones above:
  407.  
  408.     PMAP_ACTIVATE_USER(pmap, thread, cpu)
  409.     PMAP_DEACTIVATE_USER(pmap, thread, cpu)
  410.     PMAP_ACTIVATE_KERNEL(cpu)
  411.     PMAP_DEACTIVATE_KERNEL(cpu)
  412.  
  413. See the file vm/pmap.h for more details.
  414.  
  415. So now that we know how to create, activate, deactivate and destory a pmap
  416. we should add a translation to a pmap. This is done with pmap_enter().
  417.  
  418.     void pmap_enter(map, v, p, prot, wired)
  419.             register pmap_t map;
  420.             vm_offset_t     v;
  421.             vm_offset_t     p;
  422.             vm_prot_t       prot;
  423.             boolean_t       wired;
  424.  
  425. Basically you should establish a mapping for virtual address v to physical 
  426. address p with protection prot. (See mach/vm_prot.h for the protection
  427. codes). If wired is true then the page should be "wired", which means that 
  428. you must keep the translation around and you can't just chuck it. Otherwise
  429. can always just drop a translation (as long as it's not one that was set up
  430. at bootstrap time in the kernel pmap) and the MI code will provide it the
  431. next time you call vm_fault().
  432.  
  433. Actually "wired" is a leftover from the VAX. Here's the deal. On the VAX
  434. when you did I/O operations, the CPU used the virtual address to do the I/O.
  435. Some of the DMA devices actually went through the MMU and wrote into virtual
  436. addresses. This is nice of course because you don't have to do all the 
  437. scatter/gather stuff like you do with devices that DMA into physical memory.
  438. Anyway, "wired" is only asserted before an I/O operation and the page is 
  439. "unwired" after the I/O operation. 
  440.  
  441. If you're machine doesn't need a translation for I/O (say it DMAs into physical
  442. memory) then you can just ignore this wired nonsense.
  443.  
  444.         if (map == PMAP_NULL)
  445.                 return;
  446.  
  447.  
  448. Ok, now you're saying, "Hell I could 'ave read the code and gotten this much".
  449. Here's some insight. Outside of bootstrap time when the kernel is laying down
  450. kernel resident data structures, pmap_enter is *only* called because the 
  451. system took a tlb miss or a page fault and eventually called vm_fault().
  452. This means that the translation that you are being asked to insert is needed  
  453. now. Here is some more stuff. 
  454.  
  455. [discuss what to do with a split I/D tlb]
  456.  
  457. Now, the way the system removes translations is through the routine 
  458. pmap_remove(). 
  459.  
  460.     void pmap_remove(pmap, start, end)
  461.             pmap_t          pmap;
  462.             vm_offset_t     start, end;
  463.  
  464. In this call, start and end are the starting and ending virtual addresses
  465. (they are always on a page boundary). You should remove translations for
  466. all addresses va in the range start <= va < end from the specified pmap.
  467. The VM system does not try to be very smart about pmap_remove. For example,
  468. when a process is created the entire stack is "mapped" by the kernel, this 
  469. doesn't mean that pmap_enter is called, that only happens if the process
  470. actually touches the page. What I mean by mapped is that the virtual address
  471. space is set aside for the stack. Now, pmap_remove will get called to remove
  472. all of the stack. The bottom line is that it will ask for large hunks of 
  473. virtual addresses to be removed. Some (most?) of the addresses in the 
  474. region will probably not be in your pmap.
  475.  
  476. For each physical page you need to keep track if that page has been modified. 
  477. Usually this is done using a "write-trap" by the hardware. The routine 
  478. pmap_is_referenced() is given the physical address of a page and returns
  479. TRUE or FALSE.
  480.  
  481.     boolean_t pmap_is_modified(phys)
  482.             vm_offset_t     phys;
  483.  
  484. The companion routine is pmap_clear_modify which instructs the pmap module
  485. to mark the physical page as being unmodified.
  486.  
  487.     void pmap_clear_modify(phys)
  488.             vm_offset_t     phys;
  489.  
  490. Again the argument is the physical address of the page for which the modify
  491. bit should be cleared.
  492.  
  493.  
  494. Reference bits are used by the VM system to determine is a page has been 
  495. used (read/written/executed) to see if it is a candidate for page-out. 
  496. Some machines have a magic way to trigger a trap on first use (rather than
  497. just first write). If you have one of these types of machines you can use
  498. this trap to set a flag to indicate that the page has been used. If you don't
  499. have this kind of trap, you can use tlb misses or page faults to get the 
  500. information but there are better ways explained below.
  501.  
  502. There are two routines for this
  503.  
  504.     void pmap_clear_reference(phys)
  505.             vm_offset_t     phys;
  506.  
  507.     boolean_t pmap_is_referenced(phys)
  508.             vm_offset_t     phys;
  509.  
  510. The first clears the reference bit on the page, the second tests it. Presumably
  511. some trap handler sets the bit.
  512.  
  513. Rich Draves wrote a very good paper on how to deal with reference bits if the
  514. hardware doesn't have support for them. The paper is "Page Replacement and 
  515. Reference Bit Emulation in Mach." He was able to show that it's not worth
  516. the expense of putting code in the tlb handler to deal with it but instead 
  517. you can let the higher level MI code deal with the problem. You might want to
  518. read his paper in the 1991 Mach Usenix Symposium. A copy is on line at CMU
  519. in /afs/cs/project/mach/public/doc/Usenix.Mach2/page-repl.ps. It can be
  520. retrieved by FTP as user "anonymous" from mach.cs.cmu.edu from the directory
  521. doc.
  522.  
  523. If you want to use Rich's method it's really easy, just make pmap clear 
  524. reference remove all mappings for the physical page and have pmap_is_referenced
  525. always return FALSE. Since these are both really easy routines, just define
  526. them in pmap.h as follows:
  527.  
  528.     #define pmap_clear_reference(phys) \
  529.             pmap_remove_all(phys)
  530.     #define pmap_is_referenced(phys) \
  531.             (FALSE)
  532.  
  533. If you don't have hardware support for page references (both text and data)
  534. or if you have a software loaded TLB, I would implement Rich's method.
  535.  
  536. When a user program requests a change in protection on a region of virtual 
  537. address space this eventaully becomes a call to pmap_protect(). This routine
  538. is given a pmap, starting and ending virtual address and a new protection.
  539. Like pmap_remove(), not all addresses will be in your pmap data structures
  540. and you only need to change the ones that are. (You might need to flush a 
  541. tlb entry as well if there is a chance that the tlb doesn't see the change
  542. in protection in your data structures.) Anyway, same rules for ranges. 
  543. start and end are rounded to a page boundary, start at start and go up 
  544. to but not including end.
  545.  
  546.     void pmap_protect(pmap, start, end, prot)
  547.             register pmap_t pmap;
  548.             register vm_offset_t start;
  549.             vm_offset_t     end;
  550.             vm_prot_t       prot;
  551.  
  552. In order to implement copy-on-write the kernel will need to change the 
  553. protection for all virtual translations to a given physical page. In this
  554. case it calls the routine pmap_page_protect. 
  555.  
  556.     void pmap_page_protect(phys, prot)
  557.             vm_offset_t     phys;
  558.             vm_prot_t       prot;
  559.  
  560. This routine replaced two earlier routines and thus the semantics a a bit 
  561. twisted. It's really only used to LOWER permission on a page. It is also
  562. used to remove all mappings from a physical page. The idea is that if the 
  563. protection doesn't include read access then all mappings should be removed.
  564. (Yeah... this is weird, it actually makes sense on some machines to only allow
  565. execute access but that's the way it is.)
  566.  
  567.  
  568.  
  569. void pmap_change_wiring(map, v, wired)
  570.     register pmap_t    map;
  571.     vm_offset_t    v;
  572.     boolean_t    wired;
  573. /*
  574.  *    Function:    Change the wiring attribute for a map/virtual-address
  575.  *            pair.
  576.  *    In/out conditions:
  577.  *            The mapping must already exist in the pmap.
  578.  */
  579.  
  580.  
  581. kern_return_t pmap_attribute( pmap, address, size, attribute, value)
  582.         pmap_t          pmap;
  583.         vm_offset_t     address;
  584.         int             size; /* vm_size_t really, but we want it signed */
  585.         vm_machine_attribute_t  attribute;
  586.         vm_machine_attribute_val_t* value;              /* IN/OUT */
  587. /*
  588.  *      pmap_attributes:
  589.  *
  590.  *      Set/Get special memory attributes
  591.  *
  592.  */
  593.  
  594. The main (and possibly only) use of this routine is to flush pages from 
  595. whatever caches the hardware may support.
  596.  
  597.  
  598.  
  599. vm_offset_t pmap_extract(map, va)
  600.         register pmap_t         map;
  601.         vm_offset_t             va;
  602. /*
  603.  *    Function:
  604.  *        Extract the physical page address associated with the given
  605.  *        map/virtual_address pair.  The address includes the offset
  606.  *        within a page.
  607.  */
  608.  
  609. void pmap_collect(map)
  610.         register pmap_t         map;
  611. /*
  612.  *    Function:
  613.  *        Garbage collects the physical map system for
  614.  *        pages which are no longer used.
  615.  *        Success need not be guaranteed -- that is, there
  616.  *        may well be pages which are not referenced, but
  617.  *        others may be collected.
  618.  *    Usage:
  619.  *        Called by the pageout daemon when pages are scarce.
  620.  *
  621.  */
  622.  
  623.  
  624. pmap_zero_page(phys)
  625.     register vm_offset_t    phys;
  626. /*    
  627.  *    zeros the specified (machine independent) page.
  628.  */
  629.  
  630. pmap_copy_page(src, dst)
  631.     register vm_offset_t src, dst;
  632. /*    
  633.  *    copies the specified (machine independent) page.
  634.  */
  635.  
  636.  
  637. A COUPLE MORE MISCELLLANEOUS MACROS
  638.  
  639.    
  640. pmap_phys_address (code) - simple macro to convert pages to bytes
  641.  
  642. for example
  643. #define pmap_phys_address(frame) ((vm_offset_t) (intel_ptob(frame)))
  644.  
  645.  
  646.  pmap_resident_count (pmap) - returns the number of resident pages
  647.  
  648. for example
  649. #define pmap_resident_count(pmap)       ((pmap)->stats.resident_count)
  650.  
  651.  
  652. ROUTINES THAT ARE ONLY ADVISORY
  653.  
  654. pmap_copy(dst_pmap,src_pmap,dst_addr,len,src_addr)
  655.     pmap_t        dst_pmap;
  656.     pmap_t        src_pmap;
  657.     vm_offset_t    dst_addr;
  658.     int        len;
  659.     vm_offset_t    src_addr;
  660.     
  661. /*
  662.  *     Copies a section of pmap
  663.  */
  664. This routine was designed to be used as a hint at task forking
  665. time, to initialize the pmap for the new task. It does not
  666. appear to ever be called and may be removed in the near future.
  667.  
  668. pmap_pageable(map, start, end, pageable)
  669.     pmap_t        map;
  670.     vm_offset_t    start;
  671.     vm_offset_t    end;
  672.     boolean_t    pageable;
  673. /*
  674.  *    Function:
  675.  *        Make the specified pages (by pmap, offset)
  676.  *        pageable (or not) as requested.
  677.  *
  678.  *        A page which is not pageable may not take
  679.  *        a fault; therefore, its page table entry
  680.  *        must remain valid for the duration.
  681.  *
  682.  *        This routine is merely advisory; pmap_enter
  683.  *        will specify that these pages are to be wired
  684.  *        down (or not) as appropriate.
  685.  */
  686.  
  687.  
  688.  
  689.  
  690.  
  691. OBSOLETE ROUTINES
  692.  
  693. These are routines that used to be provided and you may find references
  694. to them in older documentation. They are no longer needed so
  695. don't worry about them.
  696.  
  697. pmap_access
  698. pmap_list_resident_pages
  699. pmap_remove_attributes
  700. pmap_update
  701. pmap_copy_on_write, pmap_remove_all: superceded by pmap_page_protect
  702.  
  703.