Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. #include "MMU.h"
  2.  
  3.  
  4.  
  5. void mmuTlbFlush(ArmMmu* mmu){
  6.        
  7.         UInt8 i, j;
  8.        
  9.         for(i = 0; i < MMU_TLB_BUCKET_NUM; i++){
  10.                 for(j = 0; j < MMU_TLB_BUCKET_SIZE; j++) mmu->tlb[i][j].sz = 0;
  11.                 mmu->replPos[i] = 0;
  12.                 mmu->readPos[i] = 0;
  13.         }      
  14. }
  15.  
  16.  
  17. void mmuInit(ArmMmu* mmu, ArmMmuReadF readF, void* userData){
  18.  
  19.         __mem_zero(mmu, sizeof(ArmMmu));
  20.         mmu->readF = readF;
  21.         mmu->userData = userData;
  22.         mmu->transTablPA = MMU_DISABLED_TTP;
  23.         mmu->domainCfg = 0;
  24.         mmuTlbFlush(mmu);
  25. }
  26.  
  27. void muDeinit(_UNUSED_ ArmMmu* mmu){
  28.  
  29.         //nothing here 
  30. }
  31.  
  32. static _INLINE_ UInt8 mmuPrvHashAddr(UInt32 addr){      //addresses are granular on 1K
  33.  
  34.         addr >>= 10;
  35.        
  36.         addr = addr ^ (addr >> 5) ^ (addr >> 10);
  37.        
  38.         return addr % MMU_TLB_BUCKET_NUM;
  39. }
  40.  
  41. Boolean mmuTranslate(ArmMmu* mmu, UInt32 adr, Boolean priviledged, Boolean write, UInt32* paP, UInt8* fsrP){
  42.  
  43.         UInt32 va, pa = 0, sz, t;
  44.         UInt8 i, j, dom, ap = 0;
  45.         Boolean section = false, coarse = true, pxa_tex_page = false;
  46.         UInt8 bucket;
  47.        
  48.         //handle the 'MMU off' case
  49.                
  50.         if(mmu->transTablPA == MMU_DISABLED_TTP){
  51.                 va = pa = 0;
  52.                 goto calc;
  53.         }
  54.  
  55.         //check the TLB
  56.         if(MMU_TLB_BUCKET_SIZE && MMU_TLB_BUCKET_NUM){
  57.                
  58.                 bucket = mmuPrvHashAddr(adr);
  59.                                
  60.                 for(j = 0, i = mmu->readPos[bucket]; j < MMU_TLB_BUCKET_SIZE; j++, i--){
  61.                        
  62.                         if(i == 0xFF) i = MMU_TLB_BUCKET_SIZE - 1;
  63.                        
  64.                         va = mmu->tlb[bucket][i].va;
  65.                         sz = mmu->tlb[bucket][i].sz;
  66.                        
  67.                         if(va <= adr && va + sz > adr){
  68.                                
  69.                                 pa = mmu->tlb[bucket][i].pa;
  70.                                 ap = mmu->tlb[bucket][i].ap;
  71.                                 dom = mmu->tlb[bucket][i].domain;
  72.                                 mmu->readPos[bucket] = i;
  73.                                                                
  74.                                 goto check;
  75.                         }
  76.                 }
  77.         }
  78.        
  79.         //read first level table
  80.        
  81.         if(mmu->transTablPA & 3){
  82.                 *fsrP = 0x01;   //alignment fault
  83.                 return false;
  84.         }
  85.        
  86.         if(!mmu->readF(mmu->userData, &t, mmu->transTablPA + ((adr & 0xFFF00000) >> 18))){
  87.                
  88.                 *fsrP = 0x0C;   //translation external abort first level
  89.                 return false;
  90.         }
  91.        
  92.         dom = (t >> 5) & 0x0F;
  93.         switch(t & 3){
  94.                
  95.                 case 0: //fault
  96.                
  97.                         *fsrP = 0x5;    //section translation fault
  98.                         return false;
  99.                
  100.                 case 1: //coarse pagetable
  101.                        
  102.                         t &= 0xFFFFFC00UL;
  103.                         t += (adr & 0x000FF000UL) >> 10;
  104.                         break;
  105.                
  106.                 case 2: //1MB section
  107.                
  108.                         pa = t & 0xFFF00000UL;
  109.                         va = adr & 0xFFF00000UL;
  110.                         sz = 1UL << 20;
  111.                         ap = (t >> 10) & 3;
  112.                         section = true;
  113.                         goto translated;
  114.                        
  115.                 case 3: //fine page table
  116.                        
  117.                         coarse = false;
  118.                         t &= 0xFFFFF000UL;
  119.                         t += (adr & 0x000FFC00UL) >> 8;
  120.                         break;
  121.         }
  122.        
  123.        
  124.         //read second level table
  125.        
  126.         if(!mmu->readF(mmu->userData, &t, t)){
  127.                 *fsrP = 0x0E | (dom << 4);      //translation external abort second level
  128.                 return false;
  129.         }
  130.        
  131.         switch(t & 3){
  132.                
  133.                 case 0: //fault
  134.                
  135.                         *fsrP = 0x07 | (dom << 4);      //page translation fault
  136.                         return false;
  137.                
  138.                 case 1: //64K mapping
  139.                        
  140.                         pa = t & 0xFFFF0000UL;
  141.                         va = adr & 0xFFFF0000UL;
  142.                         sz = 65536UL;
  143.                         ap = (adr >> 14) & 3;           //in "ap" store which AP we need [of the 4]
  144.                         break;
  145.                
  146.                 case 2: //4K mapping (1K effective thenks to having 4 AP fields)
  147.                
  148. page_size_4k:
  149.                         pa = t & 0xFFFFF000UL;
  150.                         va = adr & 0xFFFFF000UL;
  151.                         sz = 4096;
  152.                         ap = (adr >> 10) & 3;           //in "ap" store which AP we need [of the 4]
  153.                         break;
  154.                        
  155.                 case 3: //1K mapping
  156.                        
  157.                         if(coarse){
  158.                                
  159.                                 pxa_tex_page = true;
  160.                                 goto page_size_4k;     
  161.                         }
  162.                        
  163.                         pa = t & 0xFFFFFC00UL;
  164.                         va = adr & 0xFFFFFC00UL;
  165.                         ap = (t >> 4) & 3;              //in "ap" store the actual AP [and skip quarter-page resolution later using the goto]
  166.                         sz = 1024;
  167.                         goto translated;
  168.         }
  169.        
  170.        
  171.         //handle 4 AP sections
  172.  
  173.         i = (t >> 4) & 0xFF;
  174.         if(pxa_tex_page || ((i & 0x0F) == (i >> 4) && (i & 0x03) == ((i >> 2) & 0x03))){        //if all domains are the same, add the whole thing
  175.                
  176.                 ap = (t >> 4) & 3;
  177.         }
  178.         else{   //take the quarter that is the one we need
  179.        
  180.                 err_str("quarter page found!\r\n");
  181.                 ap = (t >> (4 + 2 * ap)) & 3;
  182.                 sz /= 4;
  183.                 pa += ((UInt32)ap) * sz;
  184.                 va += ((UInt32)ap) * sz;
  185.         }
  186.        
  187.        
  188. translated:
  189.  
  190.         //insert tlb entry
  191.         if(MMU_TLB_BUCKET_NUM && MMU_TLB_BUCKET_SIZE){
  192.                
  193.                 mmu->tlb[bucket][mmu->replPos[bucket]].pa = pa;
  194.                 mmu->tlb[bucket][mmu->replPos[bucket]].sz = sz;
  195.                 mmu->tlb[bucket][mmu->replPos[bucket]].va = va;
  196.                 mmu->tlb[bucket][mmu->replPos[bucket]].ap = ap;
  197.                 mmu->tlb[bucket][mmu->replPos[bucket]].domain = dom;
  198.                 mmu->readPos[bucket] = mmu->replPos[bucket];
  199.                 if(++mmu->replPos[bucket] == MMU_TLB_BUCKET_SIZE) mmu->replPos[bucket] = 0;
  200.         }
  201.  
  202. check:
  203.                                
  204.         //check domain permissions
  205.        
  206.         switch((mmu->domainCfg >> (dom * 2)) & 3){
  207.                
  208.                 case 0: //NO ACCESS:
  209.                 case 2: //RESERVED: unpredictable       (treat as no access)
  210.                        
  211.                         *fsrP = (section ? 0x08 : 0xB) | (dom << 4);    //section or page domain fault
  212.                         return false;
  213.                        
  214.                        
  215.                 case 1: //CLIENT: check permissions
  216.                
  217.                         break;
  218.                
  219.                        
  220.                 case 3: //MANAGER: allow all access
  221.                
  222.                         goto calc;
  223.                
  224.         }
  225.  
  226.         //check permissions
  227.        
  228.         switch(ap){
  229.                
  230.                 case 0:
  231.                
  232.                         if(write || (!mmu->R && (!priviledged || !mmu->S))) break;
  233.                         goto calc;
  234.                
  235.                 case 1:
  236.                        
  237.                         if(!priviledged) break;
  238.                         goto calc;
  239.  
  240.                 case 2:
  241.                        
  242.                         if(!priviledged && write) break;
  243.                         goto calc;
  244.                
  245.                 case 3:
  246.                
  247.                         //all is good, allow access!
  248.                         goto calc;
  249.         }
  250.        
  251. //perm_err:
  252.  
  253.         *fsrP = (section ? 0x0D : 0x0F) | (dom << 4);           //section or subpage permission fault
  254.         return false;
  255.        
  256. calc:
  257.  
  258.         *paP = adr - va + pa;
  259.         return true;
  260. }
  261.  
  262. UInt32 mmuGetTTP(ArmMmu* mmu){
  263.  
  264.         return mmu->transTablPA;
  265. }
  266.  
  267. void mmuSetTTP(ArmMmu* mmu, UInt32 ttp){
  268.  
  269.         UInt8 i;
  270.        
  271.         mmuTlbFlush(mmu);
  272.         for(i = 0; i < MMU_TLB_BUCKET_NUM; i++){
  273.                
  274.                 mmu->replPos[i] = 0;
  275.                 mmu->readPos[i] = 0;
  276.         }
  277.         mmu->transTablPA = ttp;
  278. }
  279.  
  280. void mmuSetS(ArmMmu* mmu, Boolean on){
  281.  
  282.         mmu->S = on;   
  283. }
  284.  
  285. void mmuSetR(ArmMmu* mmu, Boolean on){
  286.  
  287.         mmu->R = on;   
  288. }
  289.  
  290. Boolean mmuGetS(ArmMmu* mmu){
  291.        
  292.         return mmu->S;
  293. }
  294.  
  295. Boolean mmuGetR(ArmMmu* mmu){
  296.        
  297.         return mmu->R;
  298. }
  299.  
  300. UInt32 mmuGetDomainCfg(ArmMmu* mmu){
  301.        
  302.         return mmu->domainCfg;
  303. }
  304.  
  305. void mmuSetDomainCfg(ArmMmu* mmu, UInt32 val){
  306.        
  307.         mmu->domainCfg = val;
  308. }
  309.  
  310. ///////////////////////////  debugging helpers  ///////////////////////////
  311.  
  312.  
  313.  
  314. UInt32 mmuDR(ArmMmu* mmu, UInt32 addr){
  315.        
  316.         UInt32 t = 0;
  317.        
  318.         if(!mmu->readF(mmu->userData, &t, addr)) t = 0xFFFFFFF0UL;
  319.        
  320.         return t;
  321. }
  322.  
  323. static void mmuDumpUpdate(UInt32 va, UInt32 pa, UInt32 len, UInt8 dom, UInt8 ap, Boolean c, Boolean b, Boolean valid){
  324.        
  325.         UInt32 va_end;;
  326.        
  327.         static Boolean wasValid = false;
  328.         static UInt8 wasDom = 0;
  329.         static UInt8 wasAp = 0;
  330.         static Boolean wasB = 0;
  331.         static Boolean wasC = 0;
  332.         static UInt32 startVa = 0;
  333.         static UInt32 startPa = 0;
  334.         static UInt32 expectPa = 0;
  335.        
  336.        
  337.         va_end = (va || len) ? va - 1 : 0xFFFFFFFFUL;
  338.        
  339.         if(!wasValid && !valid) return; //no need to bother...
  340.        
  341.         if(valid != wasValid || dom != wasDom || ap != wasAp || c != wasC || b != wasB || expectPa != pa){      //not a continuation of what we've been at...
  342.                
  343.                 if(wasValid){
  344.                        
  345.                        
  346.                         err_str("0x");
  347.                         err_hex(startVa);
  348.                         err_str("-0x");
  349.                         err_hex(va_end);
  350.                         err_str(" -> 0x");
  351.                         err_hex(startPa);
  352.                         err_str("-0x");
  353.                         err_hex(startPa + (va_end - startVa));
  354.                         err_str(" dom");
  355.                         err_dec(wasDom);
  356.                         err_str(" ap");
  357.                         err_dec(wasAp);
  358.                         err_str(" ");
  359.                         err_str(wasC ? "c" : " ");
  360.                         err_str(wasB ? "b" : " ");
  361.                         err_str("\r\n");
  362.                 }
  363.                
  364.                 wasValid = valid;
  365.                 if(valid){      //start of a new range
  366.                        
  367.                         wasDom = dom;
  368.                         wasAp = ap;
  369.                         wasC = c;
  370.                         wasB = b;
  371.                         startVa = va;
  372.                         startPa = pa;
  373.                         expectPa = pa + len;
  374.                 }
  375.         }
  376.         else{   //continuation of what we've been up to...
  377.                
  378.                 expectPa += len;
  379.         }
  380. }
  381.  
  382. static void mmuDump(ArmMmu* mmu){
  383.        
  384.         UInt32 i, j, t, sla, va, psz;
  385.         UInt8 dom;
  386.         Boolean coarse = false;
  387.        
  388.         for(i = 0; i < 0x1000; i++){
  389.                
  390.                 t = mmuDR(mmu, mmu->transTablPA + (i << 2));
  391.                 va = i << 20;
  392.                 dom = (t >> 5) & 0x0F;
  393.                 switch(t & 3){
  394.                        
  395.                         case 0:         //done
  396.                                 mmuDumpUpdate(va, 0, 1UL << 20, 0, 0, false, false, false);
  397.                                 continue;
  398.                        
  399.                         case 1:         //coarse page table
  400.                                 coarse = true;
  401.                                 t &= 0xFFFFFC00UL;
  402.                                 break;
  403.                        
  404.                         case 2:         //section
  405.                                 mmuDumpUpdate(va, t & 0xFFF00000UL, 1UL << 20, dom, (t >> 10) & 3, !!(t & 8), !!(t & 4), true);
  406.                                 continue;
  407.                        
  408.                         case 3:         //fine page table
  409.                                 t &= 0xFFFFF000UL;
  410.                                 break;
  411.                 }
  412.                
  413.                 sla = t;
  414.                 psz = coarse ? 4096 : 1024;
  415.                 for(j = 0; j < ((1UL << 20) / psz); j++){
  416.                         t = mmuDR(mmu, sla + (j << 2));
  417.                         va = (i << 20) + (j * psz);
  418.                         switch(t & 3){
  419.                                
  420.                                 case 0:         //invalid
  421.                                         mmuDumpUpdate(va, 0, psz, 0, 0, false, false, false);
  422.                                         break;
  423.                                
  424.                                 case 1:         //large 64k page
  425.                                         mmuDumpUpdate(va + 0 * 16384UL, (t & 0xFFFF0000UL) + 0 * 16384UL, 16384, dom, (t >>  4) & 3, !!(t & 8), !!(t & 4), true);
  426.                                         mmuDumpUpdate(va + 1 * 16384UL, (t & 0xFFFF0000UL) + 1 * 16384UL, 16384, dom, (t >>  6) & 3, !!(t & 8), !!(t & 4), true);
  427.                                         mmuDumpUpdate(va + 2 * 16384UL, (t & 0xFFFF0000UL) + 2 * 16384UL, 16384, dom, (t >>  8) & 3, !!(t & 8), !!(t & 4), true);
  428.                                         mmuDumpUpdate(va + 3 * 16384UL, (t & 0xFFFF0000UL) + 3 * 16384UL, 16384, dom, (t >> 10) & 3, !!(t & 8), !!(t & 4), true);
  429.                                         j += coarse ? 15 : 63;
  430.                                         break;
  431.                                
  432.                                 case 2:         //small 4k page
  433.                                         mmuDumpUpdate(va + 0 * 1024, (t & 0xFFFFF000UL) + 0 * 1024, 1024, dom, (t >>  4) & 3, !!(t & 8), !!(t & 4), true);
  434.                                         mmuDumpUpdate(va + 1 * 1024, (t & 0xFFFFF000UL) + 1 * 1024, 1024, dom, (t >>  6) & 3, !!(t & 8), !!(t & 4), true);
  435.                                         mmuDumpUpdate(va + 2 * 1024, (t & 0xFFFFF000UL) + 2 * 1024, 1024, dom, (t >>  8) & 3, !!(t & 8), !!(t & 4), true);
  436.                                         mmuDumpUpdate(va + 3 * 1024, (t & 0xFFFFF000UL) + 3 * 1024, 1024, dom, (t >> 10) & 3, !!(t & 8), !!(t & 4), true);
  437.                                         if(!coarse) j += 3;
  438.                                         break;
  439.                                
  440.                                 case 3:         //tiny 1k page or TEX page on pxa
  441.                                         if(coarse){
  442.                                                
  443.                                                 mmuDumpUpdate(va, t & 0xFFFFF000UL, 4096, dom, (t >> 4) & 3, !!(t & 8), !!(t & 4), true);
  444.                                         }
  445.                                         else{
  446.                                                
  447.                                                 mmuDumpUpdate(va, t & 0xFFFFFC00UL, 1024, dom, (t >> 4) & 3, !!(t & 8), !!(t & 4), true);
  448.                                         }
  449.                                         break;
  450.                         }
  451.                 }
  452.         }
  453.         mmuDumpUpdate(0, 0, 0, 0, 0, false, false, false);      //finish things off
  454. }
  455.