File indexing completed on 2025-05-11 08:23:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 #include <rtems.h>
0067 #include <rtems/bspIo.h>
0068 #include <rtems/powerpc/powerpc.h>
0069 #include <rtems/score/sysstate.h>
0070 #include <inttypes.h>
0071 #include <stdio.h>
0072
0073 #include <bsp/mmu.h>
0074
0075
0076 #ifdef DEBUG
0077 #define STATIC
0078 #else
0079 #define STATIC static
0080 #endif
0081
0082
0083 bsp_tlb_entry_t* bsp_mmu_cache = 0;
0084
0085
0086
0087
0088
0089
0090 static void
0091 myprintf(FILE *f, char *fmt, ...)
0092 {
0093 va_list ap;
0094 va_start(ap, fmt);
0095
0096 if (!f || !_System_state_Is_up(_System_state_Get())) {
0097
0098 vprintk(fmt,ap);
0099 } else {
0100 vfprintf(f,fmt,ap);
0101 }
0102 va_end(ap);
0103 }
0104
0105
0106 void
0107 bsp_mmu_dump_cache(FILE *f)
0108 {
0109 bsp_tlb_idx_t idx;
0110 if ( !bsp_mmu_cache ) {
0111 myprintf(stderr,"MMU TLB cache not initialized\n");
0112 return;
0113 }
0114 for ( idx=0; idx<NTLBS; idx++ ) {
0115 bsp_tlb_entry_t *tlb = bsp_mmu_cache + idx;
0116 if ( !tlb->hi.v )
0117 continue;
0118 myprintf(f, "#%2i: EA 0x%08x .. 0x%08x, TID 0x%03x, EU0 0x%01x\n",
0119 idx,
0120 tlb->hi.epn << 10,
0121 (tlb->hi.epn << 10) + (1024<<(2*tlb->hi.size))-1,
0122 tlb->id.tid,
0123 tlb->hi.att);
0124 myprintf(f, " PA 0x%08"PRIx32" .. 0x%08"PRIx32", PERM 0x%03x, WIMG 0x%02x\n",
0125 tlb->lo.rpn << 10,
0126 (tlb->lo.rpn << 10) + (1024<<(2*tlb->hi.size))-1,
0127 tlb->lo.perm,
0128 tlb->lo.wimg);
0129 }
0130 }
0131
0132 static void
0133 fetch(bsp_tlb_idx_t key, bsp_tlb_entry_t* tlb)
0134 {
0135 register uint32_t tmp;
0136 __asm__ volatile (".machine \"push\" \n\t"
0137 ".machine \"any\" \n\t"
0138 "mfpid %[tmp] \n\t"
0139 "stw %[tmp],0(%[tlb]) \n\t"
0140 "tlbrehi %[tmp],%[key] \n\t"
0141 "stw %[tmp],4(%[tlb]) \n\t"
0142 "tlbrelo %[tmp],%[key] \n\t"
0143 "stw %[tmp],8(%[tlb]) \n\t"
0144 "sync \n\t"
0145 ".machine \"pop\" \n\t"
0146 : [tmp]"=&r"(tmp)
0147 : [key]"r"(key),
0148 [tlb]"b"(tlb)
0149 );
0150 }
0151
0152
0153 static void
0154 store(bsp_tlb_idx_t key, bsp_tlb_entry_t* tlb)
0155 {
0156 register uint32_t tmp;
0157 __asm__ volatile (".machine \"push\" \n\t"
0158 ".machine \"any\" \n\t"
0159 "lwz %[tmp],0(%[tlb]) \n\t"
0160 "mtpid %[tmp] \n\t"
0161 "lwz %[tmp],4(%[tlb]) \n\t"
0162 "tlbwehi %[tmp],%[key] \n\t"
0163 "lwz %[tmp],8(%[tlb]) \n\t"
0164 "tlbwelo %[tmp],%[key] \n\t"
0165 ".machine \"pop\" \n\t"
0166 : [tmp]"=&r"(tmp)
0167 : [tlb]"b"(tlb),
0168 [key]"r"(key)
0169 );
0170 }
0171
0172
0173 static void
0174 commit(void)
0175 {
0176 __asm__ volatile("isync \n\t");
0177 }
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 int
0200 bsp_mmu_update(bsp_tlb_idx_t key, bool quiet, FILE *f)
0201 {
0202 rtems_interrupt_level lvl;
0203 bsp_tlb_entry_t* tlb;
0204 bsp_tlb_idx_t idx;
0205
0206 idx = key;
0207
0208 if ( idx < 0 || idx > NTLBS-1 )
0209 return -1;
0210
0211 if (!bsp_mmu_cache)
0212 return -2;
0213
0214 tlb = bsp_mmu_cache + idx;
0215
0216 rtems_interrupt_disable(lvl);
0217
0218 fetch(idx, tlb);
0219
0220 rtems_interrupt_enable(lvl);
0221
0222 if ( tlb->hi.v ) {
0223 if ( !quiet ) {
0224
0225
0226
0227
0228
0229
0230 myprintf(f,
0231 "TLB Entry # %2d spans EA range 0x%08x - 0x%08x\n",
0232 idx,
0233 (tlb->hi.epn << 10),
0234 (tlb->hi.epn << 10) + (1024<<(2*tlb->hi.size)) - 1
0235 );
0236
0237 myprintf(f,
0238 "Mapping: VA [TID 0x%02x / EPN 0x%05x] -> RPN 0x%05"PRIx32"\n",
0239 tlb->id.tid, tlb->hi.epn, tlb->lo.rpn
0240 );
0241 myprintf(f,
0242 "Size: TSIZE 0x%x (4^sz KB = %6d KB = 0x%08x B)\n",
0243 tlb->hi.size, (1<<(2*tlb->hi.size)), (1024<<(2*tlb->hi.size))
0244 );
0245 myprintf(f,
0246 "Attributes: PERM 0x%02x (ex/wr/zsel) WIMG 0x%02x EU0 0x%01x\n",
0247 tlb->lo.perm, tlb->lo.wimg, tlb->hi.att
0248 );
0249 }
0250 } else {
0251 if ( !quiet ) {
0252 myprintf(f,
0253 "TLB Entry # %2d <OFF> (size 0x%x = 0x%xb)\n",
0254 idx, tlb->hi.size, (1024<<(2*tlb->hi.size))
0255 );
0256 }
0257 return 1;
0258 }
0259 return 0;
0260 }
0261
0262
0263
0264
0265
0266
0267 int
0268 bsp_mmu_initialize()
0269 {
0270 static bsp_tlb_entry_t mmu_cache[NTLBS];
0271 bsp_tlb_entry_t* tlb = mmu_cache;
0272 rtems_interrupt_level lvl;
0273
0274 bsp_tlb_idx_t idx;
0275 rtems_interrupt_disable(lvl);
0276 for (idx=0; idx<NTLBS; tlb++, idx++)
0277 {
0278 fetch(idx, tlb);
0279 }
0280 rtems_interrupt_enable(lvl);
0281
0282 bsp_mmu_cache = mmu_cache;
0283 return 0;
0284 }
0285
0286
0287
0288
0289
0290
0291 bsp_tlb_idx_t
0292 bsp_mmu_find_first_free()
0293 {
0294 bsp_tlb_idx_t idx;
0295 bsp_tlb_entry_t entry;
0296
0297 for (idx=0; idx<NTLBS; idx++) {
0298 register uint32_t tmp;
0299 __asm__ volatile (".machine \"push\" \n\t"
0300 ".machine \"any\" \n\t"
0301 "tlbrehi %[tmp],%[idx] \n\t"
0302 "stw %[tmp],4(%[tlb]) \n\t"
0303 "sync \n\t"
0304 ".machine \"pop\" \n\t"
0305 : [tmp]"=&r"(tmp)
0306 : [idx]"r"(idx),
0307 [tlb]"b"(&entry)
0308 : "memory"
0309 );
0310 if (!(entry.hi.v))
0311 break;
0312 }
0313 return (idx < NTLBS) ? idx : -1;
0314 }
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349 bsp_tlb_idx_t
0350 bsp_mmu_write(bsp_tlb_idx_t idx, uint32_t ea, uint32_t pa, uint sz,
0351 uint32_t flgs, uint32_t tid)
0352 {
0353 bsp_tlb_entry_t tlb;
0354 uint32_t msk;
0355 bsp_tlb_idx_t lkup;
0356 rtems_interrupt_level lvl;
0357
0358 if ( sz >= 1024 ) {
0359
0360 msk = sz;
0361 sz = 0;
0362 while ( msk != (1024u<<(2*sz)) ) {
0363 if ( ++sz > 7 ) {
0364 return -1;
0365 }
0366 }
0367
0368 }
0369
0370 msk = sz > 0 ? (1024u<<(2*sz)) - 1 : 0;
0371
0372 if ( !bsp_mmu_cache && sz > 0 ) {
0373 myprintf(stderr,"MMU driver not initialized; refusing to enable any entry\n");
0374 return -3;
0375 }
0376
0377 if ( (ea & msk) || (pa & msk) ) {
0378 myprintf(stderr,"Misaligned EA (%08x) or PA (%08x) (mask is %08x)\n", ea, pa, msk);
0379 return -1;
0380 }
0381
0382 if ( idx < 0 || idx > NTLBS-1 )
0383 return -1;
0384
0385 if ( sz > 7 ) {
0386 myprintf(stderr,"Invalid size %u = %08x = %u KB\n", sz, 1024u<<(2*sz), (1024u<<(2*sz))/1024);
0387 return -1;
0388 }
0389
0390 if ( sz >=0 ) {
0391 lkup = bsp_mmu_match(ea, sz, tid);
0392
0393 if ( lkup < -1 ) {
0394
0395 return lkup;
0396 }
0397 if ( (lkup >= 0) && (lkup != idx) && (bsp_mmu_cache[lkup].hi.v != 0) ) {
0398 myprintf(stderr,"TLB #%i overlaps with requested mapping\n", lkup);
0399 bsp_mmu_update( lkup, false, stderr);
0400 return lkup+1;
0401 }
0402 }
0403
0404
0405 tlb.id.tid = tid;
0406 tlb.hi.v = sz >= 0;
0407 tlb.hi.size = sz;
0408 tlb.hi.epn = (ea & (0xfffffc00 << (sz + sz))) >> 10;
0409 tlb.lo.rpn = (pa & (0xfffffc00 << (sz + sz))) >> 10;
0410 tlb.hi.att = (flgs & MMU_M_ATTR) >> MMU_V_ATTR;
0411 tlb.lo.perm = (flgs & MMU_M_PERM) >> MMU_V_PERM;
0412 tlb.lo.wimg = (flgs & MMU_M_PROP) >> MMU_V_PROP;
0413
0414 rtems_interrupt_disable(lvl);
0415
0416 store(idx, &tlb);
0417
0418 commit();
0419
0420 rtems_interrupt_enable(lvl);
0421
0422
0423 bsp_mmu_update(idx, true, 0);
0424
0425 return 0;
0426 }
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442 bsp_tlb_idx_t
0443 bsp_mmu_match(uint32_t ea, int sz, uint32_t tid)
0444 {
0445 bsp_tlb_idx_t idx;
0446 uint32_t m,a;
0447 bsp_tlb_entry_t* tlb;
0448
0449 if ( sz < 0 || sz > 7 )
0450 return -4;
0451
0452 sz = (1024<<(2*sz));
0453
0454 if ( !bsp_mmu_cache ) {
0455
0456 return -3;
0457 }
0458
0459 if ( ea & (sz-1) ) {
0460
0461 return -2;
0462 }
0463
0464 for ( idx=0, tlb=bsp_mmu_cache; idx<NTLBS; idx++, tlb++ ) {
0465 if ( ! tlb->hi.v )
0466 continue;
0467 if ( tlb->id.tid && tlb->id.tid != tid )
0468 continue;
0469
0470 m = (1024<<(2*tlb->hi.size)) - 1;
0471
0472 a = tlb->hi.epn << 10;
0473 if ( ea <= a + m && ea + sz -1 >= a ) {
0474
0475 return idx;
0476 }
0477 }
0478 return -1;
0479 }
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491 bsp_tlb_idx_t
0492 bsp_mmu_find(uint32_t ea, uint32_t tid)
0493 {
0494 rtems_interrupt_level lvl;
0495 register uint32_t pid;
0496 register bsp_tlb_idx_t idx;
0497 register int failure;
0498
0499 rtems_interrupt_disable(lvl);
0500
0501 __asm__ volatile (".machine \"push\"\n\t"
0502 ".machine \"any\"\n\t"
0503 "mfpid %[pid] \n\t"
0504 "mtpid %[tid] \n\t"
0505 "tlbsx. %[idx],0,%[ea] \n\t"
0506 "mfcr %[failure] \n\t"
0507 "mtpid %[pid] \n\t"
0508 ".machine \"pop\"\n\t"
0509 : [pid]"=r"(pid),
0510 [idx]"=&r"(idx),
0511 [failure]"=&r"(failure)
0512 : [tid]"r"(tid),
0513 [ea]"r"(ea)
0514 : "cc"
0515 );
0516
0517 rtems_interrupt_enable(lvl);
0518
0519 return (failure & 0x20000000) ? idx : -1;
0520 }
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532 int
0533 bsp_mmu_invalidate(bsp_tlb_idx_t key)
0534 {
0535 bsp_tlb_idx_t k0;
0536 rtems_interrupt_level lvl;
0537 bsp_tlb_entry_t tlb;
0538 uint32_t msr;
0539
0540
0541 if ( key < 0 || key > NTLBS-1 )
0542 return -1;
0543
0544 _CPU_MSR_GET(msr);
0545
0546
0547 if (msr & (PPC_MSR_IR | PPC_MSR_DR))
0548 {
0549
0550 k0 = bsp_mmu_find(0, 0);
0551 if ( -1 == k0 ) {
0552 myprintf(stderr,"No mapping for address 0 found\n");
0553 return -2;
0554 }
0555
0556
0557 if ( k0 == key ) {
0558 myprintf(stderr,"Cannot invalidate page holding address 0 (always needed)\n");
0559 return -3;
0560 }
0561 }
0562
0563 rtems_interrupt_disable(lvl);
0564
0565 fetch(key, &tlb);
0566
0567
0568 tlb.hi.v = 0;
0569
0570 store(key, &tlb);
0571
0572 commit();
0573
0574
0575 bsp_mmu_cache[ key ].hi.v = tlb.hi.v;
0576
0577 rtems_interrupt_enable(lvl);
0578
0579 return 0;
0580 }