1 #-
2 # Copyright (c) 2005 Peter Grehan
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 # 1. Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright
11 # notice, this list of conditions and the following disclaimer in the
12 # documentation and/or other materials provided with the distribution.
13 #
14 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 # SUCH DAMAGE.
25 #
26 # $FreeBSD$
27 #
28
29 #include <sys/param.h>
30 #include <sys/lock.h>
31 #include <sys/mutex.h>
32 #include <sys/systm.h>
33
34 #include <vm/vm.h>
35 #include <vm/vm_page.h>
36
37 #include <machine/mmuvar.h>
38
39 /**
40 * @defgroup MMU mmu - KObj methods for PowerPC MMU implementations
41 * @brief A set of methods required by all MMU implementations. These
42 * are basically direct call-thru's from the pmap machine-dependent
43 * code.
44 * Thanks to Bruce M Simpson's pmap man pages for routine descriptions.
45 *@{
46 */
47
48 INTERFACE mmu;
49
50 #
51 # Default implementations of some methods
52 #
53 CODE {
54 static void mmu_null_copy(mmu_t mmu, pmap_t dst_pmap, pmap_t src_pmap,
55 vm_offset_t dst_addr, vm_size_t len, vm_offset_t src_addr)
56 {
57 return;
58 }
59
60 static void mmu_null_growkernel(mmu_t mmu, vm_offset_t addr)
61 {
62 return;
63 }
64
65 static void mmu_null_init(mmu_t mmu)
66 {
67 return;
68 }
69
70 static boolean_t mmu_null_is_prefaultable(mmu_t mmu, pmap_t pmap,
71 vm_offset_t va)
72 {
73 return (FALSE);
74 }
75
76 static void mmu_null_object_init_pt(mmu_t mmu, pmap_t pmap,
77 vm_offset_t addr, vm_object_t object, vm_pindex_t index,
78 vm_size_t size)
79 {
80 return;
81 }
82
83 static void mmu_null_page_init(mmu_t mmu, vm_page_t m)
84 {
85 return;
86 }
87
88 static void mmu_null_remove_pages(mmu_t mmu, pmap_t pmap)
89 {
90 return;
91 }
92
93 static int mmu_null_mincore(mmu_t mmu, pmap_t pmap, vm_offset_t addr)
94 {
95 return (0);
96 }
97
98 static void mmu_null_deactivate(struct thread *td)
99 {
100 return;
101 }
102
103 static vm_offset_t mmu_null_addr_hint(mmu_t mmu, vm_object_t object,
104 vm_offset_t va, vm_size_t size)
105 {
106 return (va);
107 }
108 };
109
110
111 /**
112 * @brief Change the wiring attribute for the page in the given physical
113 * map and virtual address.
114 *
115 * @param _pmap physical map of page
116 * @param _va page virtual address
117 * @param _wired TRUE to increment wired count, FALSE to decrement
118 */
119 METHOD void change_wiring {
120 mmu_t _mmu;
121 pmap_t _pmap;
122 vm_offset_t _va;
123 boolean_t _wired;
124 };
125
126
127 /**
128 * @brief Clear the 'modified' bit on the given physical page
129 *
130 * @param _pg physical page
131 */
132 METHOD void clear_modify {
133 mmu_t _mmu;
134 vm_page_t _pg;
135 };
136
137
138 /**
139 * @brief Clear the 'referenced' bit on the given physical page
140 *
141 * @param _pg physical page
142 */
143 METHOD void clear_reference {
144 mmu_t _mmu;
145 vm_page_t _pg;
146 };
147
148
149 /**
150 * @brief Clear the write and modified bits in each of the given
151 * physical page's mappings
152 *
153 * @param _pg physical page
154 */
155 METHOD void remove_write {
156 mmu_t _mmu;
157 vm_page_t _pg;
158 };
159
160
161 /**
162 * @brief Copy the address range given by the source physical map, virtual
163 * address and length to the destination physical map and virtual address.
164 * This routine is optional (xxx default null implementation ?)
165 *
166 * @param _dst_pmap destination physical map
167 * @param _src_pmap source physical map
168 * @param _dst_addr destination virtual address
169 * @param _len size of range
170 * @param _src_addr source virtual address
171 */
172 METHOD void copy {
173 mmu_t _mmu;
174 pmap_t _dst_pmap;
175 pmap_t _src_pmap;
176 vm_offset_t _dst_addr;
177 vm_size_t _len;
178 vm_offset_t _src_addr;
179 } DEFAULT mmu_null_copy;
180
181
182 /**
183 * @brief Copy the source physical page to the destination physical page
184 *
185 * @param _src source physical page
186 * @param _dst destination physical page
187 */
188 METHOD void copy_page {
189 mmu_t _mmu;
190 vm_page_t _src;
191 vm_page_t _dst;
192 };
193
194
195 /**
196 * @brief Create a mapping between a virtual/physical address pair in the
197 * passed physical map with the specified protection and wiring
198 *
199 * @param _pmap physical map
200 * @param _va mapping virtual address
201 * @param _p mapping physical page
202 * @param _prot mapping page protection
203 * @param _wired TRUE if page will be wired
204 */
205 METHOD void enter {
206 mmu_t _mmu;
207 pmap_t _pmap;
208 vm_offset_t _va;
209 vm_page_t _p;
210 vm_prot_t _prot;
211 boolean_t _wired;
212 };
213
214
215 /**
216 * @brief Maps a sequence of resident pages belonging to the same object.
217 *
218 * @param _pmap physical map
219 * @param _start virtual range start
220 * @param _end virtual range end
221 * @param _m_start physical page mapped at start
222 * @param _prot mapping page protection
223 */
224 METHOD void enter_object {
225 mmu_t _mmu;
226 pmap_t _pmap;
227 vm_offset_t _start;
228 vm_offset_t _end;
229 vm_page_t _m_start;
230 vm_prot_t _prot;
231 };
232
233
234 /**
235 * @brief A faster entry point for page mapping where it is possible
236 * to short-circuit some of the tests in pmap_enter.
237 *
238 * @param _pmap physical map (and also currently active pmap)
239 * @param _va mapping virtual address
240 * @param _pg mapping physical page
241 * @param _prot new page protection - used to see if page is exec.
242 */
243 METHOD void enter_quick {
244 mmu_t _mmu;
245 pmap_t _pmap;
246 vm_offset_t _va;
247 vm_page_t _pg;
248 vm_prot_t _prot;
249 };
250
251
252 /**
253 * @brief Reverse map the given virtual address, returning the physical
254 * page associated with the address if a mapping exists.
255 *
256 * @param _pmap physical map
257 * @param _va mapping virtual address
258 *
259 * @retval 0 No mapping found
260 * @retval addr The mapping physical address
261 */
262 METHOD vm_paddr_t extract {
263 mmu_t _mmu;
264 pmap_t _pmap;
265 vm_offset_t _va;
266 };
267
268
269 /**
270 * @brief Reverse map the given virtual address, returning the
271 * physical page if found. The page must be held (by calling
272 * vm_page_hold) if the page protection matches the given protection
273 *
274 * @param _pmap physical map
275 * @param _va mapping virtual address
276 * @param _prot protection used to determine if physical page
277 * should be locked
278 *
279 * @retval NULL No mapping found
280 * @retval page Pointer to physical page. Held if protections match
281 */
282 METHOD vm_page_t extract_and_hold {
283 mmu_t _mmu;
284 pmap_t _pmap;
285 vm_offset_t _va;
286 vm_prot_t _prot;
287 };
288
289
290 /**
291 * @brief Increase kernel virtual address space to the given virtual address.
292 * Not really required for PowerPC, so optional unless the MMU implementation
293 * can use it.
294 *
295 * @param _va new upper limit for kernel virtual address space
296 */
297 METHOD void growkernel {
298 mmu_t _mmu;
299 vm_offset_t _va;
300 } DEFAULT mmu_null_growkernel;
301
302
303 /**
304 * @brief Called from vm_mem_init. Zone allocation is available at
305 * this stage so a convenient time to create zones. This routine is
306 * for MMU-implementation convenience and is optional.
307 */
308 METHOD void init {
309 mmu_t _mmu;
310 } DEFAULT mmu_null_init;
311
312
313 /**
314 * @brief Return if the page has been marked by MMU hardware to have been
315 * modified
316 *
317 * @param _pg physical page to test
318 *
319 * @retval boolean TRUE if page has been modified
320 */
321 METHOD boolean_t is_modified {
322 mmu_t _mmu;
323 vm_page_t _pg;
324 };
325
326
327 /**
328 * @brief Return whether the specified virtual address is a candidate to be
329 * prefaulted in. This routine is optional.
330 *
331 * @param _pmap physical map
332 * @param _va virtual address to test
333 *
334 * @retval boolean TRUE if the address is a candidate.
335 */
336 METHOD boolean_t is_prefaultable {
337 mmu_t _mmu;
338 pmap_t _pmap;
339 vm_offset_t _va;
340 } DEFAULT mmu_null_is_prefaultable;
341
342
343 /**
344 * @brief Return a count of referenced bits for a page, clearing those bits.
345 * Not all referenced bits need to be cleared, but it is necessary that 0
346 * only be returned when there are none set.
347 *
348 * @params _m physical page
349 *
350 * @retval int count of referenced bits
351 */
352 METHOD boolean_t ts_referenced {
353 mmu_t _mmu;
354 vm_page_t _pg;
355 };
356
357
358 /**
359 * @brief Map the requested physical address range into kernel virtual
360 * address space. The value in _virt is taken as a hint. The virtual
361 * address of the range is returned, or NULL if the mapping could not
362 * be created. The range can be direct-mapped if that is supported.
363 *
364 * @param *_virt Hint for start virtual address, and also return
365 * value
366 * @param _start physical address range start
367 * @param _end physical address range end
368 * @param _prot protection of range (currently ignored)
369 *
370 * @retval NULL could not map the area
371 * @retval addr, *_virt mapping start virtual address
372 */
373 METHOD vm_offset_t map {
374 mmu_t _mmu;
375 vm_offset_t *_virt;
376 vm_paddr_t _start;
377 vm_paddr_t _end;
378 int _prot;
379 };
380
381
382 /**
383 * @brief Used to create a contiguous set of read-only mappings for a
384 * given object to try and eliminate a cascade of on-demand faults as
385 * the object is accessed sequentially. This routine is optional.
386 *
387 * @param _pmap physical map
388 * @param _addr mapping start virtual address
389 * @param _object device-backed V.M. object to be mapped
390 * @param _pindex page-index within object of mapping start
391 * @param _size size in bytes of mapping
392 */
393 METHOD void object_init_pt {
394 mmu_t _mmu;
395 pmap_t _pmap;
396 vm_offset_t _addr;
397 vm_object_t _object;
398 vm_pindex_t _pindex;
399 vm_size_t _size;
400 } DEFAULT mmu_null_object_init_pt;
401
402
403 /**
404 * @brief Used to determine if the specified page has a mapping for the
405 * given physical map, by scanning the list of reverse-mappings from the
406 * page. The list is scanned to a maximum of 16 entries.
407 *
408 * @param _pmap physical map
409 * @param _pg physical page
410 *
411 * @retval bool TRUE if the physical map was found in the first 16
412 * reverse-map list entries off the physical page.
413 */
414 METHOD boolean_t page_exists_quick {
415 mmu_t _mmu;
416 pmap_t _pmap;
417 vm_page_t _pg;
418 };
419
420
421 /**
422 * @brief Initialise the machine-dependent section of the physical page
423 * data structure. This routine is optional.
424 *
425 * @param _pg physical page
426 */
427 METHOD void page_init {
428 mmu_t _mmu;
429 vm_page_t _pg;
430 } DEFAULT mmu_null_page_init;
431
432
433 /**
434 * @brief Initialise a physical map data structure
435 *
436 * @param _pmap physical map
437 */
438 METHOD void pinit {
439 mmu_t _mmu;
440 pmap_t _pmap;
441 };
442
443
444 /**
445 * @brief Initialise the physical map for process 0, the initial process
446 * in the system.
447 * XXX default to pinit ?
448 *
449 * @param _pmap physical map
450 */
451 METHOD void pinit0 {
452 mmu_t _mmu;
453 pmap_t _pmap;
454 };
455
456
457 /**
458 * @brief Set the protection for physical pages in the given virtual address
459 * range to the given value.
460 *
461 * @param _pmap physical map
462 * @param _start virtual range start
463 * @param _end virtual range end
464 * @param _prot new page protection
465 */
466 METHOD void protect {
467 mmu_t _mmu;
468 pmap_t _pmap;
469 vm_offset_t _start;
470 vm_offset_t _end;
471 vm_prot_t _prot;
472 };
473
474
475 /**
476 * @brief Create a mapping in kernel virtual address space for the given array
477 * of wired physical pages.
478 *
479 * @param _start mapping virtual address start
480 * @param *_m array of physical page pointers
481 * @param _count array elements
482 */
483 METHOD void qenter {
484 mmu_t _mmu;
485 vm_offset_t _start;
486 vm_page_t *_pg;
487 int _count;
488 };
489
490
491 /**
492 * @brief Remove the temporary mappings created by qenter.
493 *
494 * @param _start mapping virtual address start
495 * @param _count number of pages in mapping
496 */
497 METHOD void qremove {
498 mmu_t _mmu;
499 vm_offset_t _start;
500 int _count;
501 };
502
503
504 /**
505 * @brief Release per-pmap resources, e.g. mutexes, allocated memory etc. There
506 * should be no existing mappings for the physical map at this point
507 *
508 * @param _pmap physical map
509 */
510 METHOD void release {
511 mmu_t _mmu;
512 pmap_t _pmap;
513 };
514
515
516 /**
517 * @brief Remove all mappings in the given physical map for the start/end
518 * virtual address range. The range will be page-aligned.
519 *
520 * @param _pmap physical map
521 * @param _start mapping virtual address start
522 * @param _end mapping virtual address end
523 */
524 METHOD void remove {
525 mmu_t _mmu;
526 pmap_t _pmap;
527 vm_offset_t _start;
528 vm_offset_t _end;
529 };
530
531
532 /**
533 * @brief Traverse the reverse-map list off the given physical page and
534 * remove all mappings. Clear the PG_WRITEABLE attribute from the page.
535 *
536 * @param _pg physical page
537 */
538 METHOD void remove_all {
539 mmu_t _mmu;
540 vm_page_t _pg;
541 };
542
543
544 /**
545 * @brief Remove all mappings in the given start/end virtual address range
546 * for the given physical map. Similar to the remove method, but it used
547 * when tearing down all mappings in an address space. This method is
548 * optional, since pmap_remove will be called for each valid vm_map in
549 * the address space later.
550 *
551 * @param _pmap physical map
552 * @param _start mapping virtual address start
553 * @param _end mapping virtual address end
554 */
555 METHOD void remove_pages {
556 mmu_t _mmu;
557 pmap_t _pmap;
558 } DEFAULT mmu_null_remove_pages;
559
560
561 /**
562 * @brief Zero a physical page. It is not assumed that the page is mapped,
563 * so a temporary (or direct) mapping may need to be used.
564 *
565 * @param _pg physical page
566 */
567 METHOD void zero_page {
568 mmu_t _mmu;
569 vm_page_t _pg;
570 };
571
572
573 /**
574 * @brief Zero a portion of a physical page, starting at a given offset and
575 * for a given size (multiples of 512 bytes for 4k pages).
576 *
577 * @param _pg physical page
578 * @param _off byte offset from start of page
579 * @param _size size of area to zero
580 */
581 METHOD void zero_page_area {
582 mmu_t _mmu;
583 vm_page_t _pg;
584 int _off;
585 int _size;
586 };
587
588
589 /**
590 * @brief Called from the idle loop to zero pages. XXX I think locking
591 * constraints might be different here compared to zero_page.
592 *
593 * @param _pg physical page
594 */
595 METHOD void zero_page_idle {
596 mmu_t _mmu;
597 vm_page_t _pg;
598 };
599
600
601 /**
602 * @brief Extract mincore(2) information from a mapping. This routine is
603 * optional and is an optimisation: the mincore code will call is_modified
604 * and ts_referenced if no result is returned.
605 *
606 * @param _pmap physical map
607 * @param _addr page virtual address
608 *
609 * @retval 0 no result
610 * @retval non-zero mincore(2) flag values
611 */
612 METHOD int mincore {
613 mmu_t _mmu;
614 pmap_t _pmap;
615 vm_offset_t _addr;
616 } DEFAULT mmu_null_mincore;
617
618
619 /**
620 * @brief Perform any operations required to allow a physical map to be used
621 * before it's address space is accessed.
622 *
623 * @param _td thread associated with physical map
624 */
625 METHOD void activate {
626 mmu_t _mmu;
627 struct thread *_td;
628 };
629
630 /**
631 * @brief Perform any operations required to deactivate a physical map,
632 * for instance as it is context-switched out.
633 *
634 * @param _td thread associated with physical map
635 */
636 METHOD void deactivate {
637 mmu_t _mmu;
638 struct thread *_td;
639 } DEFAULT mmu_null_deactivate;
640
641 /**
642 * @brief Return a hint for the best virtual address to map a tentative
643 * virtual address range in a given VM object. The default is to just
644 * return the given tentative start address.
645 *
646 * @param _obj VM backing object
647 * @param _addr initial guess at virtual address
648 * @param _size size of virtual address range
649 */
650 METHOD vm_offset_t addr_hint {
651 mmu_t _mmu;
652 vm_object_t _obj;
653 vm_offset_t _addr;
654 vm_size_t _size;
655 } DEFAULT mmu_null_addr_hint;
656
657
658
659
660 /**
661 * INTERNAL INTERFACES
662 */
663
664 /**
665 * @brief Bootstrap the VM system. At the completion of this routine, the
666 * kernel will be running in it's own address space with full control over
667 * paging.
668 *
669 * @param _start start of reserved memory (obsolete ???)
670 * @param _end end of reserved memory (obsolete ???)
671 * XXX I think the intent of these was to allow
672 * the memory used by kernel text+data+bss and
673 * loader variables/load-time kld's to be carved out
674 * of available physical mem.
675 *
676 */
677 METHOD void bootstrap {
678 mmu_t _mmu;
679 vm_offset_t _start;
680 vm_offset_t _end;
681 };
682
683
684 /**
685 * @brief Create a kernel mapping for a given physical address range.
686 * Called by bus code on behalf of device drivers. The mapping does not
687 * have to be a virtual address: it can be a direct-mapped physical address
688 * if that is supported by the MMU.
689 *
690 * @param _pa start physical address
691 * @param _size size in bytes of mapping
692 *
693 * @retval addr address of mapping.
694 */
695 METHOD void * mapdev {
696 mmu_t _mmu;
697 vm_offset_t _pa;
698 vm_size_t _size;
699 };
700
701
702 /**
703 * @brief Remove the mapping created by mapdev. Called when a driver
704 * is unloaded.
705 *
706 * @param _va Mapping address returned from mapdev
707 * @param _size size in bytes of mapping
708 */
709 METHOD void unmapdev {
710 mmu_t _mmu;
711 vm_offset_t _va;
712 vm_size_t _size;
713 };
714
715
716 /**
717 * @brief Reverse-map a kernel virtual address
718 *
719 * @param _va kernel virtual address to reverse-map
720 *
721 * @retval pa physical address corresponding to mapping
722 */
723 METHOD vm_offset_t kextract {
724 mmu_t _mmu;
725 vm_offset_t _va;
726 };
727
728
729 /**
730 * @brief Map a wired page into kernel virtual address space
731 *
732 * @param _va mapping virtual address
733 * @param _pa mapping physical address
734 */
735 METHOD void kenter {
736 mmu_t _mmu;
737 vm_offset_t _va;
738 vm_offset_t _pa;
739 };
740
741
742 /**
743 * @brief Determine if the given physical address range has been direct-mapped.
744 *
745 * @param _pa physical address start
746 * @param _size physical address range size
747 *
748 * @retval bool TRUE if the range is direct-mapped.
749 */
750 METHOD boolean_t dev_direct_mapped {
751 mmu_t _mmu;
752 vm_offset_t _pa;
753 vm_size_t _size;
754 };
755
756
757 /**
758 * @brief Evaluate if a physical page has an executable mapping
759 *
760 * @param _pg physical page
761 *
762 * @retval bool TRUE if a physical mapping exists for the given page.
763 */
764 METHOD boolean_t page_executable {
765 mmu_t _mmu;
766 vm_page_t _pg;
767 };
768
Cache object: af14c2609878b9eb2162b77355bf21f0
|