File indexing completed on 2025-05-11 08:24:00
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->w0.v )
0117 continue;
0118 myprintf(f, "#%2i: EA 0x%08x .. 0x%08x, TID 0x%03x, TS %i\n",
0119 idx,
0120 tlb->w0.epn<<10,
0121 (tlb->w0.epn<<10) + (1024<<(2*tlb->w0.size))-1,
0122 tlb->id.tid,
0123 tlb->w0.ts);
0124 myprintf(f, " PA 0x%08"PRIx32", U0-3 0x%01x, WIMGE 0x%02x, PERM 0x%03x\n",
0125 tlb->w1.rpn<<10,
0126 tlb->w2.att,
0127 tlb->w2.wimge,
0128 tlb->w2.perm);
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 ("mfpid %[tmp] \n\t"
0137 "stw %[tmp],0(%[tlb]) \n\t"
0138 "tlbre %[tmp],%[key],0 \n\t"
0139 "stw %[tmp],4(%[tlb]) \n\t"
0140 "tlbre %[tmp],%[key],1 \n\t"
0141 "stw %[tmp],8(%[tlb]) \n\t"
0142 "tlbre %[tmp],%[key],2 \n\t"
0143 "stw %[tmp],12(%[tlb]) \n\t"
0144 "sync \n\t"
0145 : [tmp]"=&r"(tmp)
0146 : [key]"r"(key),
0147 [tlb]"b"(tlb)
0148 );
0149 }
0150
0151
0152 static void
0153 store(bsp_tlb_idx_t key, bsp_tlb_entry_t* tlb)
0154 {
0155 register uint32_t tmp;
0156 __asm__ volatile ("lwz %[tmp],0(%[tlb]) \n\t"
0157 "mtpid %[tmp] \n\t"
0158 "lwz %[tmp],4(%[tlb]) \n\t"
0159 "tlbwe %[tmp],%[idx],0 \n\t"
0160 "lwz %[tmp],8(%[tlb]) \n\t"
0161 "tlbwe %[tmp],%[idx],1 \n\t"
0162 "lwz %[tmp],12(%[tlb]) \n\t"
0163 "tlbwe %[tmp],%[idx],2 \n\t"
0164 : [tmp]"=&r"(tmp)
0165 : [tlb]"b"(tlb),
0166 [idx]"r"(key)
0167 );
0168 }
0169
0170
0171 static void
0172 commit(void)
0173 {
0174 __asm__ volatile("isync \n\t");
0175 }
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 int
0198 bsp_mmu_update(bsp_tlb_idx_t key, bool quiet, FILE *f)
0199 {
0200 rtems_interrupt_level lvl;
0201 bsp_tlb_entry_t* tlb;
0202 int idx;
0203
0204 idx = key;
0205
0206 if ( idx < 0 || idx > NTLBS-1 )
0207 return -1;
0208
0209 if (!bsp_mmu_cache)
0210 return -2;
0211
0212 tlb = bsp_mmu_cache + idx;
0213
0214 rtems_interrupt_disable(lvl);
0215
0216 fetch(idx, tlb);
0217
0218 rtems_interrupt_enable(lvl);
0219
0220 if ( tlb->w0.v ) {
0221 if ( !quiet ) {
0222
0223
0224
0225
0226
0227
0228 myprintf(f,
0229 "TLB Entry # %2d spans EA range 0x%08x - 0x%08x\n",
0230 idx,
0231 (tlb->w0.epn << 10),
0232 (tlb->w0.epn << 10) + (1024<<(2*tlb->w0.size)) - 1
0233 );
0234
0235 myprintf(f,
0236 "Mapping: VA [TS %d / TID 0x%02x / EPN 0x%05x] -> RPN 0x%05"PRIx32"\n",
0237 tlb->w0.ts, tlb->id.tid, tlb->w0.epn, tlb->w1.rpn
0238 );
0239 myprintf(f,
0240 "Size: TSIZE 0x%x (4^sz KB = %6d KB = 0x%08x B)\n",
0241 tlb->w0.size, (1<<(2*tlb->w0.size)), (1024<<(2*tlb->w0.size))
0242 );
0243 myprintf(f,
0244 "Properties: PERM 0x%03x (ux/uw/ur/sx/sw/sr) WIMGE 0x%02x U0-3 0x%01x\n",
0245 tlb->w2.perm, tlb->w2.wimge, tlb->w2.att
0246 );
0247 }
0248 } else {
0249 if ( !quiet ) {
0250 myprintf(f, "TLB Entry # %2d <OFF> (size 0x%x = 0x%xb)\n",
0251 idx, tlb->w0.size, (1024<<(2*tlb->w0.size)));
0252 }
0253 return 1;
0254 }
0255 return 0;
0256 }
0257
0258
0259
0260
0261
0262
0263 int
0264 bsp_mmu_initialize()
0265 {
0266 static bsp_tlb_entry_t mmu_cache[NTLBS];
0267 bsp_tlb_entry_t* tlb = mmu_cache;
0268 rtems_interrupt_level lvl;
0269
0270 bsp_tlb_idx_t idx;
0271 rtems_interrupt_disable(lvl);
0272 for (idx=0; idx<NTLBS; tlb++, idx++)
0273 {
0274 fetch(idx, tlb);
0275 }
0276 rtems_interrupt_enable(lvl);
0277
0278 bsp_mmu_cache = mmu_cache;
0279 return 0;
0280 }
0281
0282
0283
0284
0285
0286
0287 bsp_tlb_idx_t
0288 bsp_mmu_find_first_free()
0289 {
0290 bsp_tlb_idx_t idx;
0291 bsp_tlb_entry_t entry;
0292
0293 for (idx=0; idx<NTLBS; idx++) {
0294 register uint32_t tmp;
0295 __asm__ volatile ("tlbre %[tmp],%[idx],0 \n\t"
0296 "stw %[tmp],4(%[tlb]) \n\t"
0297 "sync \n\t"
0298 : [tmp]"=&r"(tmp)
0299 : [idx]"r"(idx),
0300 [tlb]"b"(&entry)
0301 : "memory"
0302 );
0303 if (!(entry.w0.v))
0304 break;
0305 }
0306 return (idx < NTLBS) ? idx : -1;
0307 }
0308
0309
0310
0311
0312
0313
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 bsp_tlb_idx_t
0345 bsp_mmu_write(bsp_tlb_idx_t idx, uint32_t ea, uint32_t pa, int sz,
0346 uint32_t flgs, uint32_t tid, uint32_t ts, uint32_t erpn)
0347 {
0348 bsp_tlb_entry_t tlb;
0349 uint32_t msk;
0350 bsp_tlb_idx_t lkup;
0351 rtems_interrupt_level lvl;
0352
0353 if ( sz >= 1024 ) {
0354
0355 msk = sz;
0356 sz = 0;
0357 while ( msk != (1024<<(sz+sz)) ) {
0358 if ( ++sz > 15 ) {
0359 return -1;
0360 }
0361 }
0362
0363 }
0364
0365 msk = sz > 0 ? (1024<<(sz+sz)) - 1 : 0;
0366
0367 if ( !bsp_mmu_cache && sz > 0 ) {
0368 myprintf(stderr,"MMU driver not initialized; refusing to enable any entry\n");
0369 return -3;
0370 }
0371
0372 if ( (ea & msk) || (pa & msk) ) {
0373 myprintf(stderr,"Misaligned EA (%08x) or PA (%08x) (mask is %08x)\n", ea, pa, msk);
0374 return -1;
0375 }
0376
0377 if ( idx < 0 || idx > NTLBS-1 )
0378 return -1;
0379
0380
0381 if ( sz == 6 || sz == 8 || sz > 9 ) {
0382 myprintf(stderr,"Invalid size %u = %08x = %u KB\n", sz, 1024<<(sz+sz), (1024<<(sz+sz))/1024);
0383 return -1;
0384 }
0385
0386 if ( sz >=0 ) {
0387 lkup = bsp_mmu_match(ea, sz, tid, ts);
0388
0389 if ( lkup < -1 ) {
0390
0391 return lkup;
0392 }
0393
0394 if ( lkup >= 0 && lkup != idx && (bsp_mmu_cache[lkup].w0.v != 0) ) {
0395 myprintf(stderr,"TLB #%i overlaps with requested mapping\n", lkup);
0396 bsp_mmu_update( lkup, false, stderr);
0397 return lkup+1;
0398 }
0399 }
0400
0401
0402 tlb.id.tid = tid;
0403 tlb.w0.v = sz >= 0;
0404 tlb.w0.ts = ts;
0405 tlb.w0.size = sz;
0406 tlb.w0.epn = (ea & (0xfffffc00 << (sz+sz))) >> 10;
0407 if (sz < 11) {
0408 tlb.w1.rpn = (pa & (0xfffffc00 << (sz+sz))) >> 10;
0409 tlb.w1.erpn = erpn;
0410 }
0411 else {
0412 sz -= 11;
0413 tlb.w1.rpn = 0;
0414 tlb.w1.erpn = (erpn & (0xf << (sz+sz))) & 0xf;
0415 }
0416 tlb.w2.att = (flgs & MMU_M_ATTR) >> MMU_V_ATTR;
0417 tlb.w2.wimge = (flgs & MMU_M_PROP) >> MMU_V_PROP;
0418 tlb.w2.perm = (flgs & MMU_M_PERM) >> MMU_V_PERM;
0419
0420 rtems_interrupt_disable(lvl);
0421
0422 store(idx, &tlb);
0423
0424 commit();
0425
0426 rtems_interrupt_enable(lvl);
0427
0428
0429 bsp_mmu_update(idx, true, 0);
0430
0431 return 0;
0432 }
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449 bsp_tlb_idx_t
0450 bsp_mmu_match(uint32_t ea, int sz, uint32_t tid, uint32_t ts)
0451 {
0452 bsp_tlb_idx_t idx;
0453 uint32_t m,a;
0454 bsp_tlb_entry_t* tlb;
0455
0456 if ( sz < 0 || sz == 6 || sz == 8 || sz > 9 )
0457 return -4;
0458
0459 sz = (1024<<(2*sz));
0460
0461 if ( !bsp_mmu_cache ) {
0462
0463 return -3;
0464 }
0465
0466 if ( ea & (sz-1) ) {
0467
0468 return -2;
0469 }
0470
0471 for ( idx=0, tlb=bsp_mmu_cache; idx<NTLBS; idx++, tlb++ ) {
0472 if ( ! tlb->w0.v )
0473 continue;
0474 if ( tlb->id.tid && tlb->id.tid != tid )
0475 continue;
0476 if ( tlb->w0.ts != ts )
0477 continue;
0478
0479 m = (1024<<(2*tlb->w0.size)) - 1;
0480
0481 a = tlb->w0.epn<<10;
0482 if ( ea <= a + m && ea + sz -1 >= a ) {
0483
0484 return idx;
0485 }
0486 }
0487 return -1;
0488 }
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501 bsp_tlb_idx_t
0502 bsp_mmu_find(uint32_t ea, uint32_t tid, uint32_t ts)
0503 {
0504 rtems_interrupt_level lvl;
0505 register uint32_t mmucr;
0506 register bsp_tlb_idx_t idx;
0507 register int failure;
0508
0509 rtems_interrupt_disable(lvl);
0510
0511 __asm__ volatile ("mfspr %[mmucr],0x3b2 \n\t"
0512 : [mmucr]"=r"(mmucr)
0513 );
0514 __asm__ volatile ("mtspr 0x3b2,%[tid] \n\t"
0515 "tlbsx. %[idx],0,%[ea] \n\t"
0516 "mfcr %[failure] \n\t"
0517 "mtspr 0x3b2,%[mmucr] \n\t"
0518 : [idx]"=&r"(idx),
0519 [failure]"=&r"(failure)
0520 : [tid]"r"((mmucr & 0xfffeff00) | (ts << 16) | tid),
0521 [ea]"r"(ea),
0522 [mmucr]"r"(mmucr)
0523 : "cc"
0524 );
0525
0526 rtems_interrupt_enable(lvl);
0527
0528 return (failure & 0x20000000) ? idx : -1;
0529 }
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541 int
0542 bsp_mmu_invalidate(bsp_tlb_idx_t key)
0543 {
0544 bsp_tlb_idx_t k0;
0545 rtems_interrupt_level lvl;
0546 bsp_tlb_entry_t tlb;
0547
0548
0549 if ( key < 0 || key > NTLBS-1 )
0550 return -1;
0551
0552
0553 k0 = bsp_mmu_find(0, 0, 0);
0554 if ( -1 == k0 ) {
0555 myprintf(stderr,"No mapping for address 0 found\n");
0556 return -2;
0557 }
0558
0559
0560 if ( k0 == key ) {
0561 myprintf(stderr,"Cannot invalidate page holding address 0 (always needed)\n");
0562 return -3;
0563 }
0564
0565 rtems_interrupt_disable(lvl);
0566
0567 fetch(key, &tlb);
0568
0569
0570 tlb.w0.v = 0;
0571
0572 store(key, &tlb);
0573
0574 commit();
0575
0576
0577 bsp_mmu_cache[ key ].w0.v = tlb.w0.v;
0578
0579 rtems_interrupt_enable(lvl);
0580
0581 return 0;
0582 }