mmu.c

Go to the documentation of this file.
00001 /*This file has been prepared for Doxygen automatic documentation generation.*/
00023 /* Copyright (c) 2006, Atmel Corporation All rights reserved.
00024  *
00025  * Redistribution and use in source and binary forms, with or without
00026  * modification, are permitted provided that the following conditions are met:
00027  *
00028  * 1. Redistributions of source code must retain the above copyright notice,
00029  * this list of conditions and the following disclaimer.
00030  *
00031  * 2. Redistributions in binary form must reproduce the above copyright notice,
00032  * this list of conditions and the following disclaimer in the documentation
00033  * and/or other materials provided with the distribution.
00034  *
00035  * 3. The name of ATMEL may not be used to endorse or promote products derived
00036  * from this software without specific prior written permission.
00037  *
00038  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
00039  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00040  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
00041  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
00042  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00043  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00044  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00045  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00046  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00047  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00048  */
00049 
00050 #include <avr32/io.h>
00051 #include "mmu.h"
00052 #include "macro.h"
00053 #include "usart.h"
00054 
00055 /* Prototypes for local functions */
00056 int mmu_add_entry(long vpn, long pfn, int pos, int type);
00057 int mmu_read_entry(long * vpn, long * pfn, int pos, int type);
00058 int mmu_get_addrmask_from_page_size(long tlbelo, long *address_mask);
00059 
00060 
00081 int mmu_init(int enable, int mode, int segmentation)
00082 {
00083     long regval = 0;
00084     long regval_read = 0;
00085 
00086     AVR32_READ_SR_REG(AVR32_MMUCR, regval);
00087 
00088     regval = (enable<<AVR32_MMUCR_E_OFFSET)|
00089         (mode<<AVR32_MMUCR_M_OFFSET)|
00090         (segmentation<<AVR32_MMUCR_S_OFFSET);
00091 
00092     AVR32_SET_SR_REG(AVR32_MMUCR, regval);
00093 
00094     AVR32_READ_SR_REG(AVR32_MMUCR, regval_read);
00095 
00096     if (regval != regval_read) {
00097         return MMU_ERROR;
00098     }
00099 
00100     return MMU_OK;
00101 }
00102 
00103 
00110 int mmu_reset()
00111 {
00112     long regval;
00113     int timer = 10;
00114 
00115     AVR32_SET_SR_REG(AVR32_MMUCR, AVR32_MMUCR_S_MASK|AVR32_MMUCR_I_MASK);
00116 
00117     /* Wait for invalidation of MMU entries */
00118     do {
00119         AVR32_READ_SR_REG(AVR32_MMUCR, regval);
00120         --timer;
00121     } while ((regval & AVR32_MMUCR_I_MASK) != 0 && timer > 0);
00122 
00123     if (regval != AVR32_MMUCR_S_MASK || timer == 0) {
00124         return MMU_ERROR;
00125     }
00126 
00127     AVR32_SET_SR_REG(AVR32_TLBARHI, 0);
00128     AVR32_SET_SR_REG(AVR32_TLBARLO, 0);
00129 
00130     return MMU_OK;
00131 }
00132 
00133 
00147 int mmu_search_virtual_ptr(void *virtual_ptr, long *physical_addr)
00148 {
00149     long addr_mask;
00150     long vpn;
00151     long pfn;
00152     int retval;
00153     int i;
00154 
00155     for (i = 0; i < MMU_DTLB_ENTRIES; i++) {
00156         /* Read the TLB entry */
00157         retval = mmu_read_entry(&vpn, &pfn, i, MMU_TLB_TYPE_DATA);
00158         if (retval != MMU_OK) {
00159             return retval;
00160         }
00161 
00162         retval = mmu_get_addrmask_from_page_size(pfn, &addr_mask);
00163         if (retval == MMU_OK) {
00164             if (((long)virtual_ptr & addr_mask) == (vpn & addr_mask)
00165                     && (vpn & AVR32_TLBEHI_V_MASK)) {
00166                 *physical_addr = (pfn & addr_mask)
00167                     |((long)virtual_ptr & ~addr_mask);
00168                 return MMU_OK;
00169             }
00170         }
00171     }
00172 
00173     for (i = 0; i < MMU_ITLB_ENTRIES; i++) {
00174         /* Read the TLB entry */
00175         retval = mmu_read_entry(&vpn, &pfn, i, MMU_TLB_TYPE_INSTRUCTION);
00176         if (retval != MMU_OK) {
00177             return retval;
00178         }
00179 
00180         retval = mmu_get_addrmask_from_page_size(pfn, &addr_mask);
00181         if (retval == MMU_OK) {
00182             if (((long)virtual_ptr & addr_mask) == (vpn & addr_mask)
00183                     && (vpn & AVR32_TLBEHI_V_MASK)) {
00184                 *physical_addr = (pfn & addr_mask)
00185                     |((long)virtual_ptr & ~addr_mask);
00186                 return MMU_OK;
00187             }
00188         }
00189     }
00190 
00191 
00192 
00193     return MMU_TLB_MISS;
00194 }
00195 
00196 
00210 int mmu_search_physical_ptr(void *physical_ptr, long *virtual_addr)
00211 {
00212     long addr_mask;
00213     long vpn;
00214     long pfn;
00215     int retval;
00216     int i;
00217 
00218     for (i = 0; i < MMU_DTLB_ENTRIES; i++) {
00219         /* Read the TLB entry */
00220         retval = mmu_read_entry(&vpn, &pfn, i, MMU_TLB_TYPE_DATA);
00221         if (retval != MMU_OK) {
00222             return retval;
00223         }
00224 
00225         retval = mmu_get_addrmask_from_page_size(pfn, &addr_mask);
00226         if (retval == MMU_OK) {
00227             if (((long)physical_ptr & addr_mask) == (pfn & addr_mask)
00228                     && (vpn & AVR32_TLBEHI_V_MASK)) {
00229                 *virtual_addr = (vpn & addr_mask)
00230                     |((long)physical_ptr & ~addr_mask);
00231                 return MMU_OK;
00232             }
00233         }
00234     }
00235 
00236     for (i = 0; i < MMU_ITLB_ENTRIES; i++) {
00237         /* Read the TLB entry */
00238         retval = mmu_read_entry(&vpn, &pfn, i, MMU_TLB_TYPE_INSTRUCTION);
00239         if (retval != MMU_OK) {
00240             return retval;
00241         }
00242 
00243         retval = mmu_get_addrmask_from_page_size(pfn, &addr_mask);
00244         if (retval == MMU_OK) {
00245             if (((long)physical_ptr & addr_mask) == (pfn & addr_mask)
00246                     && (vpn & AVR32_TLBEHI_V_MASK)) {
00247                 *virtual_addr = (vpn & addr_mask)
00248                     |((long)physical_ptr & ~addr_mask);
00249                 return MMU_OK;
00250             }
00251         }
00252     }
00253 
00254 
00255     return MMU_TLB_MISS;
00256 }
00257 
00258 
00266 int mmu_lock_entries(int entries, int type)
00267 {
00268     if (entries < 0 ||
00269             ((type == MMU_TLB_TYPE_DATA &&
00270               entries >= MMU_DTLB_ENTRIES) ||
00271              (type == MMU_TLB_TYPE_INSTRUCTION &&
00272               entries >= MMU_ITLB_ENTRIES))) {
00273         return MMU_ERROR_ARGUMENT;
00274     }
00275 
00276     long regValue = 0;
00277 
00278     AVR32_READ_SR_REG(AVR32_MMUCR, regValue);
00279 
00280     if (type == MMU_TLB_TYPE_INSTRUCTION) {
00281         regValue &= ~(AVR32_MMUCR_ILA_MASK);
00282         regValue |= (entries<<AVR32_MMUCR_ILA_OFFSET);
00283     } else {
00284         regValue &= ~(AVR32_MMUCR_DLA_MASK);
00285         regValue |= (entries<<AVR32_MMUCR_DLA_OFFSET);
00286     }
00287 
00288     AVR32_SET_SR_REG(AVR32_MMUCR, regValue);
00289 
00290     return MMU_OK;
00291 }
00292 
00293 
00304 int mmu_add_tlb_entry(long physical_addr_base,
00305         long virtual_addr_base, struct mmu_tlb_t *options)
00306 {
00307     if (!(options->valid == MMU_ENABLE
00308             || options->valid == MMU_DISABLE)) {
00309         return MMU_ERROR_ARGUMENT;
00310     }
00311     else if (!(options->type == MMU_TLB_TYPE_INSTRUCTION
00312             || options->type == MMU_TLB_TYPE_DATA)) {
00313         return MMU_ERROR_ARGUMENT;
00314     }
00315     else if (options->asid > 0xFF
00316             || options->asid < 0) {
00317         return MMU_ERROR_ARGUMENT;
00318     }
00319     else if (!(options->cachable == MMU_ENABLE
00320             || options->cachable == MMU_DISABLE)) {
00321         return MMU_ERROR_ARGUMENT;
00322     }
00323     else if (!(options->global == MMU_ENABLE
00324             || options->global == MMU_DISABLE)) {
00325         return MMU_ERROR_ARGUMENT;
00326     }
00327     else if (!(options->bufferable == MMU_ENABLE
00328             || options->bufferable == MMU_DISABLE)) {
00329         return MMU_ERROR_ARGUMENT;
00330     }
00331     else if (options->access > 0x0D
00332             || options->access < 0) {
00333         return MMU_ERROR_ARGUMENT;
00334     }
00335     else if (!(options->page_size == MMU_PAGE_SIZE_1KB
00336             || options->page_size == MMU_PAGE_SIZE_4KB
00337             || options->page_size == MMU_PAGE_SIZE_64KB
00338             || options->page_size == MMU_PAGE_SIZE_1MB)) {
00339         return MMU_ERROR_ARGUMENT;
00340     }
00341     else if (!(options->dirty == MMU_ENABLE
00342             || options->dirty == MMU_DISABLE)) {
00343         return MMU_ERROR_ARGUMENT;
00344     }
00345     else if (!(options->write_through == MMU_ENABLE
00346             || options->write_through == MMU_DISABLE)) {
00347         return MMU_ERROR_ARGUMENT;
00348     }
00349     else if (options->position < 0 ||
00350             ((options->type == MMU_TLB_TYPE_DATA &&
00351               options->position >= MMU_DTLB_ENTRIES) ||
00352              (options->type == MMU_TLB_TYPE_INSTRUCTION &&
00353               options->position >= MMU_ITLB_ENTRIES))) {
00354         return MMU_ERROR_ARGUMENT;
00355     }
00356 
00357     unsigned long vpn;
00358     unsigned long pfn;
00359     unsigned long addr_mask;
00360 
00361     if (options->page_size == MMU_PAGE_SIZE_1KB) {
00362         addr_mask = 0xFFFFFC00;
00363     }
00364     else if (options->page_size == MMU_PAGE_SIZE_4KB) {
00365         addr_mask = 0xFFFFF000;
00366     }
00367     else if (options->page_size == MMU_PAGE_SIZE_64KB) {
00368         addr_mask = 0xFFFF0000;
00369     }
00370     else if (options->page_size == MMU_PAGE_SIZE_1MB) {
00371         addr_mask = 0xFFF00000;
00372     } else {
00373         return MMU_ERROR_ARGUMENT;
00374     }
00375 
00376     vpn =
00377         (virtual_addr_base & addr_mask)|
00378         (options->valid<<AVR32_TLBEHI_V_OFFSET)|
00379         (options->type<<AVR32_TLBEHI_I_OFFSET)|
00380         (options->asid<<AVR32_TLBEHI_ASID_OFFSET);
00381 
00382     pfn =
00383         (physical_addr_base & addr_mask)|
00384         (options->cachable<<AVR32_TLBELO_C_OFFSET)|
00385         (options->global<<AVR32_TLBELO_G_OFFSET)|
00386         (options->bufferable<<AVR32_TLBELO_B_OFFSET)|
00387         (options->access<<AVR32_TLBELO_AP_OFFSET)|
00388         (options->page_size<<AVR32_TLBELO_SZ_OFFSET)|
00389         (options->dirty<<AVR32_TLBELO_D_OFFSET)|
00390         (options->write_through<<AVR32_TLBELO_W_OFFSET);
00391 
00392     int retVal = MMU_OK;
00393 
00394     retVal = mmu_add_entry(vpn, pfn, options->position, options->type);
00395 
00396     return retVal;
00397 }
00398 
00399 
00406 void mmu_read_bear_and_tlbehi(long *bear, long *vpn)
00407 {
00408     AVR32_READ_SR_REG(AVR32_TLBEAR, *bear);
00409     AVR32_READ_SR_REG(AVR32_TLBEHI, *vpn);
00410 }
00411 
00412 
00424 int mmu_find_index_to_entry(long physical_addr, long virtual_addr, long *index)
00425 {
00426     long vpn = virtual_addr & 0xFFFFfc00;
00427     long pfn = physical_addr & 0xFFFFfc00;
00428 
00429     AVR32_SET_SR_REG(AVR32_TLBEHI, vpn);
00430     AVR32_SET_SR_REG(AVR32_TLBELO, pfn);
00431 
00432 #ifdef __GNUC__
00433     __builtin_tlbs();
00434 #elif __ICCAVR32__
00435     __search_TLB_entry();
00436 #else
00437 #error No known compiler used
00438 #endif
00439 
00440     long regValue = 0;
00441 
00442     AVR32_READ_SR_REG(AVR32_MMUCR, regValue);
00443 
00444     if ((regValue & AVR32_MMUCR_N_MASK) != 0) {
00445         return MMU_TLB_MISS;
00446     }
00447 
00448     /* Check for instruction or data TBL */
00449     if ((vpn & AVR32_TLBEHI_I_MASK) != 0) {
00450         *index = 0x3F & (regValue>>AVR32_MMUCR_IRP_OFFSET);
00451     } else {
00452         *index = 0x3F & (regValue>>AVR32_MMUCR_DRP_OFFSET);
00453     }
00454 
00455     return MMU_OK;
00456 }
00457 
00458 
00470 int mmu_invalidate_entry(int index, int type)
00471 {
00472     if (index < 0 ||
00473             ((type == MMU_TLB_TYPE_DATA &&
00474               index >= MMU_DTLB_ENTRIES) ||
00475              (type == MMU_TLB_TYPE_INSTRUCTION &&
00476               index >= MMU_ITLB_ENTRIES))) {
00477         return MMU_ERROR_ARGUMENT;
00478     }
00479 
00480     long regValue = 0;
00481 
00482     AVR32_READ_SR_REG(AVR32_MMUCR, regValue);
00483 
00484     if (type == MMU_TLB_TYPE_INSTRUCTION) {
00485         regValue &= ~(0x3F<<AVR32_MMUCR_IRP_OFFSET);
00486         regValue |= (index<<AVR32_MMUCR_IRP_OFFSET);
00487     } else {
00488         regValue &= ~(0x3F<<AVR32_MMUCR_DRP_OFFSET);
00489         regValue |= (index<<AVR32_MMUCR_DRP_OFFSET);
00490     }
00491 
00492     AVR32_SET_SR_REG(AVR32_MMUCR, regValue);
00493 
00494 #ifdef __GNUC__
00495     __builtin_tlbr();
00496 #elif __ICCAVR32__
00497     __read_TLB_entry();
00498 #else
00499 #error No known compiler used
00500 #endif
00501 
00502     AVR32_CLEAR_SR_BIT(AVR32_TLBEHI, AVR32_TLBEHI_V_OFFSET);
00503 
00504 #ifdef __GNUC__
00505     __builtin_tlbw();
00506 #elif __ICCAVR32__
00507     __write_TLB_entry();
00508 #else
00509 #error No known compiler used
00510 #endif
00511 
00512     return MMU_OK;
00513 }
00514 
00515 
00529 int mmu_add_entry(long vpn, long pfn, int pos, int type)
00530 {
00531 
00532     if (pos < 0 ||
00533             ((type == MMU_TLB_TYPE_DATA &&
00534               pos >= MMU_DTLB_ENTRIES) ||
00535              (type == MMU_TLB_TYPE_INSTRUCTION &&
00536               pos >= MMU_ITLB_ENTRIES))) {
00537         return MMU_ERROR_ARGUMENT;
00538     }
00539 
00540     long regValue = 0;
00541 
00542     AVR32_READ_SR_REG(AVR32_MMUCR, regValue);
00543 
00544     regValue &= 0x0000001F;
00545 
00546     if (type == MMU_TLB_TYPE_INSTRUCTION) {
00547         regValue |= (pos<<AVR32_MMUCR_IRP_OFFSET);
00548     }
00549     else if (type == MMU_TLB_TYPE_DATA) {
00550         regValue |= (pos<<AVR32_MMUCR_DRP_OFFSET);
00551     } else {
00552         return MMU_ERROR_ARGUMENT;
00553     }
00554 
00555     AVR32_SET_SR_REG(AVR32_MMUCR, regValue);
00556     AVR32_SET_SR_REG(AVR32_TLBEHI, vpn);
00557     AVR32_SET_SR_REG(AVR32_TLBELO, pfn);
00558 
00559 #ifdef __GNUC__
00560     __builtin_tlbw();
00561 #elif __ICCAVR32__
00562     __write_TLB_entry();
00563 #else
00564 #error No known compiler used
00565 #endif
00566 
00567     return MMU_OK;
00568 }
00569 
00570 
00585 int mmu_read_entry(long *vpn, long *pfn, int pos, int type)
00586 {
00587     long regValue = 0;
00588     if (pos < 0 ||
00589             ((type == MMU_TLB_TYPE_DATA &&
00590               pos >= MMU_DTLB_ENTRIES) ||
00591              (type == MMU_TLB_TYPE_INSTRUCTION &&
00592               pos >= MMU_ITLB_ENTRIES))) {
00593         return MMU_ERROR_ARGUMENT;
00594     }
00595 
00596     AVR32_READ_SR_REG(AVR32_MMUCR, regValue);
00597 
00598     if (type== MMU_TLB_TYPE_INSTRUCTION) {
00599         regValue &= ~(0x3F<<AVR32_MMUCR_IRP_OFFSET);
00600         regValue |= (pos<<AVR32_MMUCR_IRP_OFFSET);
00601     } else {
00602         regValue &= ~(0x3F<<AVR32_MMUCR_DRP_OFFSET);
00603         regValue |= (pos<<AVR32_MMUCR_DRP_OFFSET);
00604     }
00605 
00606     AVR32_SET_SR_REG(AVR32_MMUCR, regValue);
00607 
00608 #ifdef __GNUC__
00609     __builtin_tlbr();
00610 #elif __ICCAVR32__
00611     __read_TLB_entry();
00612 #else
00613 #error No known compiler used
00614 #endif
00615 
00616     AVR32_READ_SR_REG(AVR32_TLBEHI, *vpn);
00617     AVR32_READ_SR_REG(AVR32_TLBELO, *pfn);
00618 
00619     return MMU_OK;
00620 }
00621 
00622 
00633 int mmu_get_addrmask_from_page_size(long tlbelo, long *address_mask)
00634 {
00635     int page_size = (tlbelo & AVR32_TLBELO_SZ_MASK) >> AVR32_TLBELO_SZ_OFFSET;
00636 
00637     if (page_size == MMU_PAGE_SIZE_1KB) {
00638         *address_mask = 0xFFFFfc00;
00639     }
00640     else if (page_size == MMU_PAGE_SIZE_4KB) {
00641         *address_mask = 0xFFFFf000;
00642     }
00643     else if (page_size == MMU_PAGE_SIZE_64KB) {
00644         *address_mask = 0xFFFF0000;
00645     }
00646     else if (page_size == MMU_PAGE_SIZE_1MB) {
00647         *address_mask = 0xFFF00000;
00648     } else {
00649         return MMU_ERROR_ARGUMENT;
00650     }
00651 
00652     return MMU_OK;
00653 }
00654 

Generated on Thu Oct 18 09:30:01 2007 for AVR32113 Configuration and Use of the Memory Management Unit by  doxygen 1.5.3