mmu_if.m revision 198341
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: head/sys/powerpc/powerpc/mmu_if.m 198341 2009-10-21 18:38:02Z marcel $ 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 48INTERFACE mmu; 49 50# 51# Default implementations of some methods 52# 53CODE { 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 void mmu_null_align_superpage(mmu_t mmu, vm_object_t object, 104 vm_ooffset_t offset, vm_offset_t *addr, vm_size_t size) 105 { 106 return; 107 } 108 109 static struct pmap_md *mmu_null_scan_md(mmu_t mmu, struct pmap_md *p) 110 { 111 return (NULL); 112 } 113}; 114 115 116/** 117 * @brief Change the wiring attribute for the page in the given physical 118 * map and virtual address. 119 * 120 * @param _pmap physical map of page 121 * @param _va page virtual address 122 * @param _wired TRUE to increment wired count, FALSE to decrement 123 */ 124METHOD void change_wiring { 125 mmu_t _mmu; 126 pmap_t _pmap; 127 vm_offset_t _va; 128 boolean_t _wired; 129}; 130 131 132/** 133 * @brief Clear the 'modified' bit on the given physical page 134 * 135 * @param _pg physical page 136 */ 137METHOD void clear_modify { 138 mmu_t _mmu; 139 vm_page_t _pg; 140}; 141 142 143/** 144 * @brief Clear the 'referenced' bit on the given physical page 145 * 146 * @param _pg physical page 147 */ 148METHOD void clear_reference { 149 mmu_t _mmu; 150 vm_page_t _pg; 151}; 152 153 154/** 155 * @brief Clear the write and modified bits in each of the given 156 * physical page's mappings 157 * 158 * @param _pg physical page 159 */ 160METHOD void remove_write { 161 mmu_t _mmu; 162 vm_page_t _pg; 163}; 164 165 166/** 167 * @brief Copy the address range given by the source physical map, virtual 168 * address and length to the destination physical map and virtual address. 169 * This routine is optional (xxx default null implementation ?) 170 * 171 * @param _dst_pmap destination physical map 172 * @param _src_pmap source physical map 173 * @param _dst_addr destination virtual address 174 * @param _len size of range 175 * @param _src_addr source virtual address 176 */ 177METHOD void copy { 178 mmu_t _mmu; 179 pmap_t _dst_pmap; 180 pmap_t _src_pmap; 181 vm_offset_t _dst_addr; 182 vm_size_t _len; 183 vm_offset_t _src_addr; 184} DEFAULT mmu_null_copy; 185 186 187/** 188 * @brief Copy the source physical page to the destination physical page 189 * 190 * @param _src source physical page 191 * @param _dst destination physical page 192 */ 193METHOD void copy_page { 194 mmu_t _mmu; 195 vm_page_t _src; 196 vm_page_t _dst; 197}; 198 199 200/** 201 * @brief Create a mapping between a virtual/physical address pair in the 202 * passed physical map with the specified protection and wiring 203 * 204 * @param _pmap physical map 205 * @param _va mapping virtual address 206 * @param _p mapping physical page 207 * @param _prot mapping page protection 208 * @param _wired TRUE if page will be wired 209 */ 210METHOD void enter { 211 mmu_t _mmu; 212 pmap_t _pmap; 213 vm_offset_t _va; 214 vm_page_t _p; 215 vm_prot_t _prot; 216 boolean_t _wired; 217}; 218 219 220/** 221 * @brief Maps a sequence of resident pages belonging to the same object. 222 * 223 * @param _pmap physical map 224 * @param _start virtual range start 225 * @param _end virtual range end 226 * @param _m_start physical page mapped at start 227 * @param _prot mapping page protection 228 */ 229METHOD void enter_object { 230 mmu_t _mmu; 231 pmap_t _pmap; 232 vm_offset_t _start; 233 vm_offset_t _end; 234 vm_page_t _m_start; 235 vm_prot_t _prot; 236}; 237 238 239/** 240 * @brief A faster entry point for page mapping where it is possible 241 * to short-circuit some of the tests in pmap_enter. 242 * 243 * @param _pmap physical map (and also currently active pmap) 244 * @param _va mapping virtual address 245 * @param _pg mapping physical page 246 * @param _prot new page protection - used to see if page is exec. 247 */ 248METHOD void enter_quick { 249 mmu_t _mmu; 250 pmap_t _pmap; 251 vm_offset_t _va; 252 vm_page_t _pg; 253 vm_prot_t _prot; 254}; 255 256 257/** 258 * @brief Reverse map the given virtual address, returning the physical 259 * page associated with the address if a mapping exists. 260 * 261 * @param _pmap physical map 262 * @param _va mapping virtual address 263 * 264 * @retval 0 No mapping found 265 * @retval addr The mapping physical address 266 */ 267METHOD vm_paddr_t extract { 268 mmu_t _mmu; 269 pmap_t _pmap; 270 vm_offset_t _va; 271}; 272 273 274/** 275 * @brief Reverse map the given virtual address, returning the 276 * physical page if found. The page must be held (by calling 277 * vm_page_hold) if the page protection matches the given protection 278 * 279 * @param _pmap physical map 280 * @param _va mapping virtual address 281 * @param _prot protection used to determine if physical page 282 * should be locked 283 * 284 * @retval NULL No mapping found 285 * @retval page Pointer to physical page. Held if protections match 286 */ 287METHOD vm_page_t extract_and_hold { 288 mmu_t _mmu; 289 pmap_t _pmap; 290 vm_offset_t _va; 291 vm_prot_t _prot; 292}; 293 294 295/** 296 * @brief Increase kernel virtual address space to the given virtual address. 297 * Not really required for PowerPC, so optional unless the MMU implementation 298 * can use it. 299 * 300 * @param _va new upper limit for kernel virtual address space 301 */ 302METHOD void growkernel { 303 mmu_t _mmu; 304 vm_offset_t _va; 305} DEFAULT mmu_null_growkernel; 306 307 308/** 309 * @brief Called from vm_mem_init. Zone allocation is available at 310 * this stage so a convenient time to create zones. This routine is 311 * for MMU-implementation convenience and is optional. 312 */ 313METHOD void init { 314 mmu_t _mmu; 315} DEFAULT mmu_null_init; 316 317 318/** 319 * @brief Return if the page has been marked by MMU hardware to have been 320 * modified 321 * 322 * @param _pg physical page to test 323 * 324 * @retval boolean TRUE if page has been modified 325 */ 326METHOD boolean_t is_modified { 327 mmu_t _mmu; 328 vm_page_t _pg; 329}; 330 331 332/** 333 * @brief Return whether the specified virtual address is a candidate to be 334 * prefaulted in. This routine is optional. 335 * 336 * @param _pmap physical map 337 * @param _va virtual address to test 338 * 339 * @retval boolean TRUE if the address is a candidate. 340 */ 341METHOD boolean_t is_prefaultable { 342 mmu_t _mmu; 343 pmap_t _pmap; 344 vm_offset_t _va; 345} DEFAULT mmu_null_is_prefaultable; 346 347 348/** 349 * @brief Return a count of referenced bits for a page, clearing those bits. 350 * Not all referenced bits need to be cleared, but it is necessary that 0 351 * only be returned when there are none set. 352 * 353 * @params _m physical page 354 * 355 * @retval int count of referenced bits 356 */ 357METHOD boolean_t ts_referenced { 358 mmu_t _mmu; 359 vm_page_t _pg; 360}; 361 362 363/** 364 * @brief Map the requested physical address range into kernel virtual 365 * address space. The value in _virt is taken as a hint. The virtual 366 * address of the range is returned, or NULL if the mapping could not 367 * be created. The range can be direct-mapped if that is supported. 368 * 369 * @param *_virt Hint for start virtual address, and also return 370 * value 371 * @param _start physical address range start 372 * @param _end physical address range end 373 * @param _prot protection of range (currently ignored) 374 * 375 * @retval NULL could not map the area 376 * @retval addr, *_virt mapping start virtual address 377 */ 378METHOD vm_offset_t map { 379 mmu_t _mmu; 380 vm_offset_t *_virt; 381 vm_paddr_t _start; 382 vm_paddr_t _end; 383 int _prot; 384}; 385 386 387/** 388 * @brief Used to create a contiguous set of read-only mappings for a 389 * given object to try and eliminate a cascade of on-demand faults as 390 * the object is accessed sequentially. This routine is optional. 391 * 392 * @param _pmap physical map 393 * @param _addr mapping start virtual address 394 * @param _object device-backed V.M. object to be mapped 395 * @param _pindex page-index within object of mapping start 396 * @param _size size in bytes of mapping 397 */ 398METHOD void object_init_pt { 399 mmu_t _mmu; 400 pmap_t _pmap; 401 vm_offset_t _addr; 402 vm_object_t _object; 403 vm_pindex_t _pindex; 404 vm_size_t _size; 405} DEFAULT mmu_null_object_init_pt; 406 407 408/** 409 * @brief Used to determine if the specified page has a mapping for the 410 * given physical map, by scanning the list of reverse-mappings from the 411 * page. The list is scanned to a maximum of 16 entries. 412 * 413 * @param _pmap physical map 414 * @param _pg physical page 415 * 416 * @retval bool TRUE if the physical map was found in the first 16 417 * reverse-map list entries off the physical page. 418 */ 419METHOD boolean_t page_exists_quick { 420 mmu_t _mmu; 421 pmap_t _pmap; 422 vm_page_t _pg; 423}; 424 425 426/** 427 * @brief Initialise the machine-dependent section of the physical page 428 * data structure. This routine is optional. 429 * 430 * @param _pg physical page 431 */ 432METHOD void page_init { 433 mmu_t _mmu; 434 vm_page_t _pg; 435} DEFAULT mmu_null_page_init; 436 437 438/** 439 * @brief Count the number of managed mappings to the given physical 440 * page that are wired. 441 * 442 * @param _pg physical page 443 * 444 * @retval int the number of wired, managed mappings to the 445 * given physical page 446 */ 447METHOD int page_wired_mappings { 448 mmu_t _mmu; 449 vm_page_t _pg; 450}; 451 452 453/** 454 * @brief Initialise a physical map data structure 455 * 456 * @param _pmap physical map 457 */ 458METHOD void pinit { 459 mmu_t _mmu; 460 pmap_t _pmap; 461}; 462 463 464/** 465 * @brief Initialise the physical map for process 0, the initial process 466 * in the system. 467 * XXX default to pinit ? 468 * 469 * @param _pmap physical map 470 */ 471METHOD void pinit0 { 472 mmu_t _mmu; 473 pmap_t _pmap; 474}; 475 476 477/** 478 * @brief Set the protection for physical pages in the given virtual address 479 * range to the given value. 480 * 481 * @param _pmap physical map 482 * @param _start virtual range start 483 * @param _end virtual range end 484 * @param _prot new page protection 485 */ 486METHOD void protect { 487 mmu_t _mmu; 488 pmap_t _pmap; 489 vm_offset_t _start; 490 vm_offset_t _end; 491 vm_prot_t _prot; 492}; 493 494 495/** 496 * @brief Create a mapping in kernel virtual address space for the given array 497 * of wired physical pages. 498 * 499 * @param _start mapping virtual address start 500 * @param *_m array of physical page pointers 501 * @param _count array elements 502 */ 503METHOD void qenter { 504 mmu_t _mmu; 505 vm_offset_t _start; 506 vm_page_t *_pg; 507 int _count; 508}; 509 510 511/** 512 * @brief Remove the temporary mappings created by qenter. 513 * 514 * @param _start mapping virtual address start 515 * @param _count number of pages in mapping 516 */ 517METHOD void qremove { 518 mmu_t _mmu; 519 vm_offset_t _start; 520 int _count; 521}; 522 523 524/** 525 * @brief Release per-pmap resources, e.g. mutexes, allocated memory etc. There 526 * should be no existing mappings for the physical map at this point 527 * 528 * @param _pmap physical map 529 */ 530METHOD void release { 531 mmu_t _mmu; 532 pmap_t _pmap; 533}; 534 535 536/** 537 * @brief Remove all mappings in the given physical map for the start/end 538 * virtual address range. The range will be page-aligned. 539 * 540 * @param _pmap physical map 541 * @param _start mapping virtual address start 542 * @param _end mapping virtual address end 543 */ 544METHOD void remove { 545 mmu_t _mmu; 546 pmap_t _pmap; 547 vm_offset_t _start; 548 vm_offset_t _end; 549}; 550 551 552/** 553 * @brief Traverse the reverse-map list off the given physical page and 554 * remove all mappings. Clear the PG_WRITEABLE attribute from the page. 555 * 556 * @param _pg physical page 557 */ 558METHOD void remove_all { 559 mmu_t _mmu; 560 vm_page_t _pg; 561}; 562 563 564/** 565 * @brief Remove all mappings in the given start/end virtual address range 566 * for the given physical map. Similar to the remove method, but it used 567 * when tearing down all mappings in an address space. This method is 568 * optional, since pmap_remove will be called for each valid vm_map in 569 * the address space later. 570 * 571 * @param _pmap physical map 572 * @param _start mapping virtual address start 573 * @param _end mapping virtual address end 574 */ 575METHOD void remove_pages { 576 mmu_t _mmu; 577 pmap_t _pmap; 578} DEFAULT mmu_null_remove_pages; 579 580 581/** 582 * @brief Zero a physical page. It is not assumed that the page is mapped, 583 * so a temporary (or direct) mapping may need to be used. 584 * 585 * @param _pg physical page 586 */ 587METHOD void zero_page { 588 mmu_t _mmu; 589 vm_page_t _pg; 590}; 591 592 593/** 594 * @brief Zero a portion of a physical page, starting at a given offset and 595 * for a given size (multiples of 512 bytes for 4k pages). 596 * 597 * @param _pg physical page 598 * @param _off byte offset from start of page 599 * @param _size size of area to zero 600 */ 601METHOD void zero_page_area { 602 mmu_t _mmu; 603 vm_page_t _pg; 604 int _off; 605 int _size; 606}; 607 608 609/** 610 * @brief Called from the idle loop to zero pages. XXX I think locking 611 * constraints might be different here compared to zero_page. 612 * 613 * @param _pg physical page 614 */ 615METHOD void zero_page_idle { 616 mmu_t _mmu; 617 vm_page_t _pg; 618}; 619 620 621/** 622 * @brief Extract mincore(2) information from a mapping. This routine is 623 * optional and is an optimisation: the mincore code will call is_modified 624 * and ts_referenced if no result is returned. 625 * 626 * @param _pmap physical map 627 * @param _addr page virtual address 628 * 629 * @retval 0 no result 630 * @retval non-zero mincore(2) flag values 631 */ 632METHOD int mincore { 633 mmu_t _mmu; 634 pmap_t _pmap; 635 vm_offset_t _addr; 636} DEFAULT mmu_null_mincore; 637 638 639/** 640 * @brief Perform any operations required to allow a physical map to be used 641 * before it's address space is accessed. 642 * 643 * @param _td thread associated with physical map 644 */ 645METHOD void activate { 646 mmu_t _mmu; 647 struct thread *_td; 648}; 649 650/** 651 * @brief Perform any operations required to deactivate a physical map, 652 * for instance as it is context-switched out. 653 * 654 * @param _td thread associated with physical map 655 */ 656METHOD void deactivate { 657 mmu_t _mmu; 658 struct thread *_td; 659} DEFAULT mmu_null_deactivate; 660 661/** 662 * @brief Return a hint for the best virtual address to map a tentative 663 * virtual address range in a given VM object. The default is to just 664 * return the given tentative start address. 665 * 666 * @param _obj VM backing object 667 * @param _offset starting offset with the VM object 668 * @param _addr initial guess at virtual address 669 * @param _size size of virtual address range 670 */ 671METHOD void align_superpage { 672 mmu_t _mmu; 673 vm_object_t _obj; 674 vm_ooffset_t _offset; 675 vm_offset_t *_addr; 676 vm_size_t _size; 677} DEFAULT mmu_null_align_superpage; 678 679 680 681 682/** 683 * INTERNAL INTERFACES 684 */ 685 686/** 687 * @brief Bootstrap the VM system. At the completion of this routine, the 688 * kernel will be running in it's own address space with full control over 689 * paging. 690 * 691 * @param _start start of reserved memory (obsolete ???) 692 * @param _end end of reserved memory (obsolete ???) 693 * XXX I think the intent of these was to allow 694 * the memory used by kernel text+data+bss and 695 * loader variables/load-time kld's to be carved out 696 * of available physical mem. 697 * 698 */ 699METHOD void bootstrap { 700 mmu_t _mmu; 701 vm_offset_t _start; 702 vm_offset_t _end; 703}; 704 705/** 706 * @brief Set up the MMU on the current CPU. Only called by the PMAP layer 707 * for alternate CPUs on SMP systems. 708 * 709 * @param _ap Set to 1 if the CPU being set up is an AP 710 * 711 */ 712METHOD void cpu_bootstrap { 713 mmu_t _mmu; 714 int _ap; 715}; 716 717 718/** 719 * @brief Create a kernel mapping for a given physical address range. 720 * Called by bus code on behalf of device drivers. The mapping does not 721 * have to be a virtual address: it can be a direct-mapped physical address 722 * if that is supported by the MMU. 723 * 724 * @param _pa start physical address 725 * @param _size size in bytes of mapping 726 * 727 * @retval addr address of mapping. 728 */ 729METHOD void * mapdev { 730 mmu_t _mmu; 731 vm_offset_t _pa; 732 vm_size_t _size; 733}; 734 735 736/** 737 * @brief Remove the mapping created by mapdev. Called when a driver 738 * is unloaded. 739 * 740 * @param _va Mapping address returned from mapdev 741 * @param _size size in bytes of mapping 742 */ 743METHOD void unmapdev { 744 mmu_t _mmu; 745 vm_offset_t _va; 746 vm_size_t _size; 747}; 748 749 750/** 751 * @brief Reverse-map a kernel virtual address 752 * 753 * @param _va kernel virtual address to reverse-map 754 * 755 * @retval pa physical address corresponding to mapping 756 */ 757METHOD vm_offset_t kextract { 758 mmu_t _mmu; 759 vm_offset_t _va; 760}; 761 762 763/** 764 * @brief Map a wired page into kernel virtual address space 765 * 766 * @param _va mapping virtual address 767 * @param _pa mapping physical address 768 */ 769METHOD void kenter { 770 mmu_t _mmu; 771 vm_offset_t _va; 772 vm_offset_t _pa; 773}; 774 775 776/** 777 * @brief Determine if the given physical address range has been direct-mapped. 778 * 779 * @param _pa physical address start 780 * @param _size physical address range size 781 * 782 * @retval bool TRUE if the range is direct-mapped. 783 */ 784METHOD boolean_t dev_direct_mapped { 785 mmu_t _mmu; 786 vm_offset_t _pa; 787 vm_size_t _size; 788}; 789 790 791/** 792 * @brief Enforce instruction cache coherency. Typically called after a 793 * region of memory has been modified and before execution of or within 794 * that region is attempted. Setting breakpoints in a process through 795 * ptrace(2) is one example of when the instruction cache needs to be 796 * made coherent. 797 * 798 * @param _pm the physical map of the virtual address 799 * @param _va the virtual address of the modified region 800 * @param _sz the size of the modified region 801 */ 802METHOD void sync_icache { 803 mmu_t _mmu; 804 pmap_t _pm; 805 vm_offset_t _va; 806 vm_size_t _sz; 807}; 808 809 810/** 811 * @brief Create temporary memory mapping for use by dumpsys(). 812 * 813 * @param _md The memory chunk in which the mapping lies. 814 * @param _ofs The offset within the chunk of the mapping. 815 * @param _sz The requested size of the mapping. 816 * 817 * @retval vm_offset_t The virtual address of the mapping. 818 * 819 * The sz argument is modified to reflect the actual size of the 820 * mapping. 821 */ 822METHOD vm_offset_t dumpsys_map { 823 mmu_t _mmu; 824 struct pmap_md *_md; 825 vm_size_t _ofs; 826 vm_size_t *_sz; 827}; 828 829 830/** 831 * @brief Remove temporary dumpsys() mapping. 832 * 833 * @param _md The memory chunk in which the mapping lies. 834 * @param _ofs The offset within the chunk of the mapping. 835 * @param _va The virtual address of the mapping. 836 */ 837METHOD void dumpsys_unmap { 838 mmu_t _mmu; 839 struct pmap_md *_md; 840 vm_size_t _ofs; 841 vm_offset_t _va; 842}; 843 844 845/** 846 * @brief Scan/iterate memory chunks. 847 * 848 * @param _prev The previously returned chunk or NULL. 849 * 850 * @retval The next (or first when _prev is NULL) chunk. 851 */ 852METHOD struct pmap_md * scan_md { 853 mmu_t _mmu; 854 struct pmap_md *_prev; 855} DEFAULT mmu_null_scan_md; 856