source: rtems/c/src/lib/libcpu/powerpc/e500/mmu/mmu.c @ ac7af4a

4.104.115
Last change on this file since ac7af4a was e08dbc5, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 11/03/09 at 18:45:04

various PowerPC code maintenance

  • Property mode set to 100644
File size: 21.4 KB
Line 
1/* $Id$ */
2
3/*
4 * Routines to manipulate e500 TLBs; TLB0 (fixed 4k page size)
5 * is not very useful so we mostly focus on TLB1 (variable page size).
6 *
7 * TLB0's 256 entries are 2-way set associative which means that
8 *        only 2 entries for page index numbers with matching 7 LSBs
9 *        are available.
10 *
11 *        E.g., look at EA = 0xAAAyy000. 0xAAAyy is the page index.
12 *
13 *        The least-significant 7 bits in 'yy' determine the 'way'
14 *        in the TLB 0 array. At most two EAs with matching 'yy' bits
15 *        (the 7 LSBs, that is) can be mapped with TLB0 since there
16 *        are only two entries per 'way'.
17 *
18 *        Since this is a real-time OS we want to stay away from
19 *        software TLB replacement.
20 */
21
22/*
23 * Authorship
24 * ----------
25 * This software was created by
26 *     Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
27 *         Stanford Linear Accelerator Center, Stanford University.
28 *
29 * Acknowledgement of sponsorship
30 * ------------------------------
31 * This software was produced by
32 *     the Stanford Linear Accelerator Center, Stanford University,
33 *         under Contract DE-AC03-76SFO0515 with the Department of Energy.
34 *
35 * Government disclaimer of liability
36 * ----------------------------------
37 * Neither the United States nor the United States Department of Energy,
38 * nor any of their employees, makes any warranty, express or implied, or
39 * assumes any legal liability or responsibility for the accuracy,
40 * completeness, or usefulness of any data, apparatus, product, or process
41 * disclosed, or represents that its use would not infringe privately owned
42 * rights.
43 *
44 * Stanford disclaimer of liability
45 * --------------------------------
46 * Stanford University makes no representations or warranties, express or
47 * implied, nor assumes any liability for the use of this software.
48 *
49 * Stanford disclaimer of copyright
50 * --------------------------------
51 * Stanford University, owner of the copyright, hereby disclaims its
52 * copyright and all other rights in this software.  Hence, anyone may
53 * freely use it for any purpose without restriction. 
54 *
55 * Maintenance of notices
56 * ----------------------
57 * In the interest of clarity regarding the origin and status of this
58 * SLAC software, this and all the preceding Stanford University notices
59 * are to remain affixed to any copy or derivative of this software made
60 * or distributed by the recipient and are to be affixed to any copy of
61 * software made or distributed by the recipient that contains a copy or
62 * derivative of this software.
63 *
64 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
65 */
66
67/* 8450 MSR definitions; note that there are *substantial* differences
68 * compared to classic powerpc; in particular, IS/DS are *different*
69 * from IR/DR; the e500 MMU can not be switched off!
70 *
71 * Also: To disable/enable all external interrupts, CE and EE must both be
72 *       controlled.
73 */
74#include <rtems.h>
75#include <rtems/bspIo.h>
76#include <inttypes.h>
77#include <stdio.h>
78
79#include "e500_mmu.h"
80
81#if 0
82#define MSR_UCLE        (1<<(63-37)) /* User-mode cache lock      PPC: ?                     */
83#define MSR_SPE         (1<<(63-38)) /* SPE enable                PPC: VE   (altivec)        */
84#define MSR_WE          (1<<(63-45)) /* Wait state enable         PPC: POW  (pwr. mgmt)      */
85#define MSR_CE          (1<<(63-46)) /* Critical-interrupt enable PPC: TGPR (TLBupdt in use) */
86#define MSR_EE          (1<<(63-48)) /* External-interrupt enable PPC: EE                    */
87#define MSR_PR          (1<<(63-49)) /* User mode                 PPC: PR                    */
88#define MSR_ME          (1<<(63-51)) /* Machine-check enable      PPC: ME                    */
89#define MSR_UBLE        (1<<(63-53)) /* User BTB lock enable      PPC: SE   (sstep enable)   */
90#define MSR_DE          (1<<(63-54)) /* Debug-interrupt enable    PPC: BE   (br. tr. enbl)   */
91#define MSR_IS          (1<<(63-58)) /* Instruction address space PPC: IR   (inst. MMU enbl) */
92#define MSR_DS          (1<<(63-59)) /* Data address space        PPC: DR   (data MMU enbl)  */
93#define MSR_PMM         (1<<(63-61)) /* Performance-monitor mark  PPC: ?                     */
94#endif
95
96/* Bit definitions for MAS registers                                             */
97#define SPR_MAS0                624
98#define MAS0_TLBSEL             (           1  << (63-35))      /* Which TLB to access       */
99#define MAS0_ESEL(n)    ( (0xf & (n))  << (63-47))      /* Selected TLB entry        */
100#define MAS0_ESEL_RD(m) ( ((m) >> (63-47)) & 0xf )
101#define MAS0_NV                 (           1  << (63-63))      /* Next victim               */
102
103#define SPR_MAS1                625
104#define MAS1_V                  (           1  << (63-32))      /* Entry valid               */
105#define MAS1_IPROT              (           1  << (63-33))      /* Invalidate protect        */
106#define MAS1_TID(n)             ( (0xff & (n)) << (63-47))      /* Translation ID            */
107#define MAS1_TID_GET(n) ( ((n) >> (63-47)) & 0xfff)
108
109#define MAS1_TS                 (           1  << (63-51))      /* Translation space         */
110#define MAS1_TSIZE(n)   ( (0xf & (n))  << (63-55))      /* Translation ID            */
111#define MAS1_TSIZE_GET(n) ( ((n)>>(63-55)) & 0xf)
112
113#define SPR_MAS2                626
114#define MAS2_EPN(n)             ( (((1<<21)-1)&(n)) << (63-51)) /* EPN                   */
115#define MAS2_EPN_GET(n) (((n)>>(63-51)) & 0xfffff)
116#define MAS2_X0                 (           1  << (63-57))      /* Attr. 0                   */
117#define MAS2_X1                 (           1  << (63-58))      /* Attr. 1                   */
118#define MAS2_W                  (           1  << (63-59))      /* Write-through             */
119#define MAS2_I                  (           1  << (63-60))      /* Cache-inhibited           */
120#define MAS2_M                  (           1  << (63-61))      /* Memory-coherence req.     */
121#define MAS2_G                  (           1  << (63-62))      /* Guarded                   */
122#define MAS2_E                  (           1  << (63-63))      /* Little-endian             */
123#define MAS2_ATTR(x)    ( (x) & 0x7f )
124#define MAS2_ATTR_GET(x) ( (x) & 0x7f )
125
126#define SPR_MAS3                627
127#define MAS3_RPN(n)             ( (((1<<21)-1)&(n)) << (63-51)) /* RPN                   */
128#define MAS3_RPN_GET(n) (((n)>>(63-51)) & 0xfffff)
129#define MAS3_U0                 (           1  << (63-54))      /* User attr. 0              */
130#define MAS3_U1                 (           1  << (63-55))      /* User attr. 1              */
131#define MAS3_U2                 (           1  << (63-56))      /* User attr. 2              */
132#define MAS3_U3                 (           1  << (63-57))      /* User attr. 3              */
133#define MAS3_UX                 (           1  << (63-58))      /* User  exec.               */
134#define MAS3_SX                 (           1  << (63-59))      /* Super exec.               */
135#define MAS3_UW                 (           1  << (63-60))      /* User  write               */
136#define MAS3_SW                 (           1  << (63-61))      /* Super write               */
137#define MAS3_UR                 (           1  << (63-62))      /* User  read                */
138#define MAS3_SR                 (           1  << (63-63))      /* Super read                */
139
140#define MAS3_PERM(n)    ( (n) & 0x3ff )
141#define MAS3_PERM_GET(n) ( (n) & 0x3ff )
142
143#define SPR_MAS4                628
144#define MAS4_TLBSELD    (           1  << (63-35))      /* TLBSEL default            */
145#define MAS4_TIDSELD(n) ( (0x3 & (n))  << (63-47))      /* TID default               */
146#define MAS4_TSIZED(n)  ( (0xf & (n))  << (63-55))      /* TSIZE default             */
147#define MAS4_X0D                MAS2_X0
148#define MAS4_X1D                MAS2_X1
149#define MAS4_WD                 MAS2_W
150#define MAS4_ID                 MAS2_I
151#define MAS4_MD                 MAS2_M
152#define MAS4_GD                 MAS2_G
153#define MAS4_ED                 MAS2_E
154
155#define SPR_MAS6                630
156#define MAS6_SPID0(n)   ( (0xff & (n)) << (63-55))      /* PID used for search       */
157#define MAS6_SAS                (           1  << (63-63))      /* AS for search             */
158
159#define SPR_PID0                48
160#define SPR_PID1                633
161#define SPR_PID2                634
162
163#define TLBIVAX_TLBSEL  (1<<(63-60))
164#define TLBIVAX_INV_ALL (1<<(63-61))
165
166#define E500_TLB_ATTR_WIMGE(x)      ((x)&0x7f)                          /* includes user bits */
167#define E500_TLB_ATTR_WIMGE_GET(x)  ((x)&0x7f)
168#define E500_TLB_ATTR_TS            (1<<7)
169#define E500_TLB_ATTR_PERM(x)           (((x)&0x3ff)<<8)
170#define E500_TLB_ATTR_PERM_GET(x)   (((x)>>8)&0x3ff)
171#define E500_TLB_ATTR_TID(x)        (((x)&0xfff)<<20)
172#define E500_TLB_ATTR_TID_GET(x)    (((x)>>20)&0xfff)
173
174
175#ifdef DEBUG
176#define STATIC
177#else
178#define STATIC static
179#endif
180
181/* Factory to generate inline macros for accessing the MAS registers */
182#define __RDWRMAS(mas,rmas)     \
183        static inline uint32_t _read_MAS##mas(void)                                      \
184        { uint32_t x; asm volatile("mfspr %0, %1": "=r"(x):"i"(rmas)); return x; } \
185        static inline void _write_MAS##mas(uint32_t x)                             \
186        {             asm volatile("mtspr %1, %0":: "r"(x),"i"(rmas)); }
187
188__RDWRMAS(0,SPR_MAS0)
189__RDWRMAS(1,SPR_MAS1)
190__RDWRMAS(2,SPR_MAS2)
191__RDWRMAS(3,SPR_MAS3)
192__RDWRMAS(4,SPR_MAS4)
193__RDWRMAS(6,SPR_MAS6)
194
195#undef __RDWRMAS
196
197static int initialized  = 0;
198
199E500_tlb_va_cache_t rtems_e500_tlb_va_cache[16] = { {{0}},};
200
201/* Since it is likely that these routines are used during
202 * early initialization when stdio is not available yet
203 * we provide a helper that resorts to 'printk()'
204 */
205static void
206myprintf(FILE *f, char *fmt, ...)
207{
208va_list ap;
209    va_start(ap, fmt);
210
211    if (!f || !_impure_ptr->__sdidinit) {
212        /*
213                 * Might be called at an early stage when
214         * stdio is not yet initialized.
215         */
216        vprintk(fmt,ap);
217    } else {
218        vfprintf(f,fmt,ap);
219    }
220    va_end(ap);
221}
222
223
224void
225rtems_e500_dmptlbc(FILE *f)
226{
227int i;
228        if ( !initialized ) {
229                myprintf(stderr,"TLB cache not initialized\n");
230                return;
231        }
232        for ( i=0; i<16; i++ ) {
233                if ( !rtems_e500_tlb_va_cache[i].att.v )
234                        continue;       
235                myprintf(f,"#%2i: TID 0x%03x, TS %i, ea 0x%08x .. 0x%08x\n",
236                        i,
237                        rtems_e500_tlb_va_cache[i].va.va_tid,
238                        rtems_e500_tlb_va_cache[i].att.ts,
239                        rtems_e500_tlb_va_cache[i].va.va_epn<<12,
240                        (rtems_e500_tlb_va_cache[i].va.va_epn<<12) + (1024<<(2*rtems_e500_tlb_va_cache[i].att.sz))-1);
241                myprintf(f,"PA 0x%08"PRIx32", PERM 0x%03x, WIMGE 0x%02x\n",
242                        rtems_e500_tlb_va_cache[i].rpn<<12,
243                        rtems_e500_tlb_va_cache[i].att.perm,
244                        rtems_e500_tlb_va_cache[i].att.wimge);
245        }
246}
247
248#define E500_SELTLB_1   0x1000
249
250static void seltlb(rtems_e500_tlb_idx key)
251{
252int idx = key & ~E500_SELTLB_1;
253
254        if ( key & E500_SELTLB_1 ) {
255                _write_MAS0( MAS0_TLBSEL | MAS0_ESEL(idx) );
256        } else {
257                _write_MAS0( (idx & 128) ? MAS0_ESEL(1) : MAS0_ESEL(0) );
258                _write_MAS2( MAS2_EPN( idx & 127 ) );
259        }
260}
261
262/*
263 * Read a TLB entry from the hardware; if it is a TLB1 entry
264 * then the current settings are stored in the
265 * rtems_e500_tlb_va_cache[] structure.
266 *
267 * The routine can perform this operation quietly or
268 * print information to a file.
269 *
270 *   'sel': which TLB array to use; TLB0 (4k) if zero,
271 *          TLB1 (variable) if nonzero.
272 *   'idx': which TLB entry to access.
273 * 'quiet': perform operation silently (no info printed)
274 *          if nonzero.
275 *     'f': open FILE where to print information. May be
276 *          NULL in which case 'stdout' is used.
277 *
278 * RETURNS:
279 *       0: success; TLB entry is VALID
280 *      +1: success but TLB entry is INVALID
281 *     < 0: error (-1: invalid argument)
282 */
283int
284rtems_e500_prtlb(rtems_e500_tlb_idx key, int quiet, FILE *f)
285{
286uint32_t               mas0, mas1, mas2, mas3;
287rtems_interrupt_level  lvl;
288E500_tlb_va_cache_t   *tlb;
289E500_tlb_va_cache_t    buf;
290int                    sel, idx;
291
292        sel = (key &  E500_SELTLB_1) ? 1 : 0;
293        idx = key & ~E500_SELTLB_1;
294
295        if ( idx < 0 || idx > 255 || ( idx > 15 && sel ) )
296                return -1;
297
298        rtems_interrupt_disable(lvl);
299
300        seltlb( key );
301
302        asm volatile("tlbre");
303
304        mas0 = _read_MAS0();
305        mas1 = _read_MAS1();
306        mas2 = _read_MAS2();
307        mas3 = _read_MAS3();
308
309        rtems_interrupt_enable(lvl);
310
311        tlb = sel ? rtems_e500_tlb_va_cache + idx : &buf;
312
313        if ( (tlb->att.v  = (MAS1_V & mas1) ? 1 : 0) ) {
314                tlb->va.va_epn = MAS2_EPN_GET(mas2);
315                tlb->rpn       = MAS3_RPN_GET(mas3);
316                tlb->va.va_tid = MAS1_TID_GET(mas1);
317                tlb->att.ts    = (MAS1_TS & mas1) ? 1 : 0;
318                tlb->att.sz    = sel ? MAS1_TSIZE_GET(mas1) : 1 /* 4k size */;
319                tlb->att.wimge = MAS2_ATTR_GET(mas2);
320                tlb->att.perm  = MAS3_PERM_GET(mas3);
321        }
322
323        if ( tlb->att.v ) {
324                if ( !quiet ) {
325/*
326                        "TLB[1] Entry # 0 spans EA range     0x00000000 .. 0x00000000
327                        "Mapping:    VA     [TS 0/TID 0x00/EPN 0x00000] -> RPN 0x00000"
328                        "Size:       TSIZE  0x0 ( 4^ts KiB = 000000 KiB = 0x00000000 B)
329                        "Attributes: PERM 0x000 (ux/sx/uw/sw/ur/sr) WIMGE 0x00 IPROT 0"
330*/
331                        myprintf(f,
332                                "TLB[%i] Entry # %d spans EA range     0x%08x .. 0x%08x\r\n",
333                                sel,
334                                idx,
335                                (tlb->va.va_epn << 12),
336                                (tlb->va.va_epn << 12) + (1024<<(2*tlb->att.sz)) - 1
337                        );
338
339                        myprintf(f,
340                                "Mapping:    VA     [TS %d/TID 0x%02x/EPN 0x%05x] -> RPN 0x%05"PRIx32"\r\n",
341                                tlb->att.ts, tlb->va.va_tid, tlb->va.va_epn, tlb->rpn
342                        );
343                        myprintf(f,
344                                "Size:       TSIZE  0x%x ( 4^ts KiB = %6d KiB = 0x%08x B)\r\n",
345                                tlb->att.sz, (1<<(2*tlb->att.sz)), (1024<<(2*tlb->att.sz))
346                        );
347                        myprintf(f,
348                                "Attributes: PERM 0x%03x (ux/sx/uw/sw/ur/sr) WIMGE 0x%02x IPROT %i\r\n",
349                                tlb->att.perm, tlb->att.wimge, (sel && (mas1 & MAS1_IPROT) ? 1 : 0)
350                        );
351                        myprintf(f,
352                                "EA range 0x%08x .. 0x%08x\r\n",
353                                (tlb->va.va_epn << 12),
354                                (tlb->va.va_epn << 12) + (1024<<(2*tlb->att.sz)) - 1
355                        );
356                }
357        } else {
358                if ( !quiet ) {
359                        myprintf(f, "TLB[%i] Entry #%i <OFF> (size 0x%x = 0x%xb)\n", sel, idx, tlb->att.sz, (1024<<(2*tlb->att.sz)));
360                }
361                return 1;
362        }
363        return 0;
364}
365
366/* Initialize cache; verify that TLB0 is unused;
367 *
368 * RETURNS: zero on success, nonzero on error (TLB0
369 *          seems to be in use); in this case the
370 *          driver will refuse to change TLB1 entries
371 *          (other than disabling them).
372 */
373int rtems_e500_initlb()
374{
375int i;
376int rval = 0;
377        for (i=0; i<16; i++)
378                rtems_e500_prtlb(E500_SELTLB_1 | i, 1, 0);
379        for (i=0; i<256; i++) {
380                /* refuse to enable operations that change TLB entries
381         * if anything in TLB[0] is valid (because we currently
382                 * don't check against overlap with TLB[0] when we
383                 * write a new entry).
384                 */
385                if ( rtems_e500_prtlb(E500_SELTLB_0 | i, 1, 0) <=0 ) {
386                        myprintf(stderr,"WARNING: 4k TLB #%i seems to be valid; UNSUPPORTED configuration\n", i);
387                        rval = -1;
388                }
389        }
390        if ( !rval )
391                initialized = 1;
392        return rval;
393}
394
395/*
396 * Write TLB1 entry (can also be used to disable an entry).
397 *
398 * The routine checks against the cached data in
399 * rtems_e500_tlb_va[] to prevent the user from generating
400 * overlapping entries.
401 *
402 *   'idx': TLB 1 entry # to manipulate
403 *    'ea': Effective address (must be page aligned)
404 *    'pa': Physical  address (must be page aligned)
405 *    'sz': Page size selector; page size is
406 *          1024 * 2^(2*sz) bytes.
407 *          'sz' may also be one of the following:
408 *          - page size in bytes ( >= 1024 ); the selector
409 *            value is then computed by this routine.
410 *            However, 'sz' must be a valid page size
411 *            or -1 will be returned.
412 *          - a value < 0 to invalidate/disable the
413 *            TLB entry.
414 *  'attr': Page attributes; ORed combination of WIMGE,
415 *          PERMissions, TID and TS. Use ATTR_xxx macros
416 *
417 * RETURNS: 0 on success, nonzero on error:
418 *
419 *         >0: requested mapping would overlap with
420 *             existing mapping in other entry. Return
421 *             value gives conflicting entry + 1; i.e.,
422 *             if a value of 4 is returned then the request
423 *             conflicts with existing mapping in entry 3.
424 *         -1: invalid argument
425 *         -3: driver not initialized (or initialization
426 *             failed because TLB0 is in use).
427 *         <0: other error
428 *
429 */
430#define E500_TLB_ATTR_WIMGE(x)      ((x)&0x7f)                          /* includes user bits */
431#define E500_TLB_ATTR_WIMGE_GET(x)  ((x)&0x7f)
432#define E500_TLB_ATTR_TS            (1<<7)
433#define E500_TLB_ATTR_PERM(x)              (((x)&0x3ff)<<8)
434#define E500_TLB_ATTR_PERM_GET(x)   (((x)>>8)&0x3ff)
435#define E500_TLB_ATTR_TID(x)        (((x)&0xfff)<<20)
436#define E500_TLB_ATTR_TID_GET(x)    (((x)>>20)&0xfff)
437
438int
439rtems_e500_wrtlb(int idx, uint32_t ea, uint32_t pa, int sz, uint32_t attr)
440{
441uint32_t              mas1, mas2, mas3, mas4;
442uint32_t              tid, msk;
443int                   lkup;
444rtems_interrupt_level lvl;
445
446        if ( sz >= 1024 ) {
447                /* Assume they literally specify a size */
448                msk = sz;
449                sz  = 0;
450                while ( msk != (1024<<(2*sz)) ) {
451                        if ( ++sz > 15 ) {
452                                return -1;
453                        }
454                }
455                /* OK, acceptable */
456        }
457
458        msk = sz > 0 ? (1024<<(2*sz)) - 1 : 0;
459
460        if ( !initialized && sz > 0 ) {
461                myprintf(stderr,"TLB driver not initialized; refuse to enable any entry\n");
462                return -3;
463        }
464
465        if ( (ea & msk) || (pa & msk) ) {
466                myprintf(stderr,"Misaligned ea or pa\n");
467                return -1;
468        }
469
470        if ( idx < 0 || idx > 15 )
471                return -1;
472
473        if ( sz > 15 ) {
474                /* but e500v1 doesn't support all 16 sizes!! */
475                /* FIXME: we should inquire about this CPU's
476                 *        capabilities...
477                 */
478                return -1;
479        }
480
481        tid = E500_TLB_ATTR_TID_GET(attr);
482
483        mas1 = (attr & E500_TLB_ATTR_TS) ? MAS1_TS : 0;
484
485        if ( sz >=0 ) {
486                lkup = rtems_e500_matchtlb(ea, tid, mas1, sz);
487
488                if ( lkup < -1 ) {
489                        /* some error */
490                        return lkup;
491                }
492
493                if ( lkup >= 0 && lkup != idx ) {
494                        myprintf(stderr,"TLB[1] #%i overlaps with requested mapping\n", lkup);
495                        rtems_e500_prtlb( E500_SELTLB_1 | lkup, 0, stderr);
496                        return lkup+1;
497                }
498        }
499
500        /* OK to proceed */
501        mas1 |= MAS1_IPROT | MAS1_TID(tid);
502
503        if ( sz >= 0 )
504                mas1 |= MAS1_V | MAS1_TSIZE(sz);
505
506        mas2 = MAS2_EPN( ea>>12 ) | E500_TLB_ATTR_WIMGE(attr);
507        mas3 = MAS3_RPN( pa>>12 ) | E500_TLB_ATTR_PERM_GET(attr);
508        /* mas4 is not really relevant; we don't use TLB replacement */
509        mas4 = MAS4_TLBSELD | MAS4_TIDSELD(0) | MAS4_TSIZED(9) | MAS4_ID | MAS4_GD;
510
511        rtems_interrupt_disable(lvl);
512
513        seltlb(idx | E500_SELTLB_1);
514
515        _write_MAS1(mas1);
516        _write_MAS2(mas2);
517        _write_MAS3(mas3);
518        _write_MAS4(mas4);
519
520        asm volatile(
521                "       sync            \n"
522                "       isync           \n"
523                "       tlbwe       \n"
524                "       sync        \n"
525                "       isync           \n"
526        );
527
528        rtems_interrupt_enable(lvl);
529
530        /* update cache */
531        rtems_e500_prtlb( E500_SELTLB_1 | idx, 1, 0);
532
533        return 0;
534}
535
536/*
537 * Check if a ts/tid/ea/sz mapping overlaps
538 * with an existing entry.
539 *
540 * ASSUMPTION: all TLB0 (fixed 4k pages) are invalid and always unused.
541 *
542 * NOTE: 'sz' is the 'logarithmic' size selector; the page size
543 *       is 1024*2^(2*sz).
544 *
545 * RETURNS:
546 *     >= 0: index of TLB1 entry that already provides a mapping
547 *           which overlaps within the ea range.
548 *       -1: SUCCESS (no conflicting entry found)
549 *     <=-2: ERROR (invalid input)
550 */
551int rtems_e500_matchtlb(uint32_t ea, uint32_t tid, int ts, int sz)
552{
553int                  i;
554uint32_t             m,a;
555E500_tlb_va_cache_t *tlb;
556
557        if ( sz < 0 || sz > 15 )
558                return -4;
559
560        sz = (1024<<(2*sz));
561
562        if ( !initialized ) {
563                /* cache not initialized */
564                return -3;
565        }
566
567        if ( ea & (sz-1) ) {
568                /* misaligned ea */
569                return -2;
570        }
571
572        if ( ts )
573                ts = 1;
574
575        for ( i=0, tlb=rtems_e500_tlb_va_cache; i<16; i++, tlb++ ) {
576                if ( ! tlb->att.v )
577                        continue;
578                if ( tlb->att.ts != ts )
579                        continue;
580                if ( tlb->va.va_tid && tlb->va.va_tid != tid )
581                        continue;
582                /* TID and TS match a valid entry */
583                m  = (1024<<(2*tlb->att.sz)) - 1;
584                /* calculate starting address of this entry */
585                a  = tlb->va.va_epn<<12;
586                if ( ea <= a + m && ea + sz -1 >= a ) {
587                        /* overlap */
588                        return i;
589                }
590        }
591        return -1;
592}
593
594/* Find TLB index that maps 'ea/as' combination
595 *
596 * RETURNS: index 'key'; i.e., the index number plus
597 *          a bit (E500_SELTLB_1) which indicates whether
598 *          the mapping was found in TLB0 (4k fixed page
599 *          size) or in TLB1 (variable page size).
600 *
601 *          On error (no mapping) -1 is returned.
602 */
603rtems_e500_tlb_idx
604rtems_e500_ftlb(uint32_t ea, int as)
605{
606uint32_t              pid, mas0, mas1;
607int                   i, rval = -1;
608rtems_interrupt_level lvl;
609
610        rtems_interrupt_disable(lvl);
611
612        for ( i=0; i<3; i++ ) {
613                switch (i) {
614                        case 0: asm volatile("mfspr %0, %1":"=r"(pid):"i"(SPR_PID0)); break;
615                        case 1: asm volatile("mfspr %0, %1":"=r"(pid):"i"(SPR_PID1)); break;
616                        case 2: asm volatile("mfspr %0, %1":"=r"(pid):"i"(SPR_PID2)); break;
617                        default:
618                                goto bail;
619                }
620
621                _write_MAS6( MAS6_SPID0(pid) | (as ? MAS6_SAS : 0 ) );
622
623                asm volatile("tlbsx 0, %0"::"r"(ea));
624
625                mas1 = _read_MAS1();
626
627                if ( (MAS1_V & mas1) ) {
628                        mas0 = _read_MAS0();
629                        if ( MAS0_TLBSEL & mas0 ) {
630                                /* TLB1 */
631                                rval = MAS0_ESEL_RD(mas0) | E500_SELTLB_1;
632                        } else {
633                                rval = (ea >> (63-51)) | (( MAS0_NV & mas0 ) ? 180 : 0 ) ;
634                        }
635                        break;
636                }
637        }
638
639bail:
640        rtems_interrupt_enable(lvl);
641        return rval;
642}
643
644/* Mark TLB entry as invalid ('disabled'). Unlike
645 * rtems_e500_wrtlb() with a negative size argument
646 * this routine also can disable TLB0 entries.
647 *
648 * 'key': TLB entry (index) ORed with selector bit
649 *        (0 for TLB0, E500_SELTLB_1 for TLB1).
650 *
651 * RETURNS: zero on success, nonzero on error (TLB
652 *          unchanged).
653 *
654 * NOTE:  If a TLB1 entry is disabled the associated
655 *        entry in rtems_e500_va_cache[] is also
656 *        marked as disabled.
657 */
658int
659rtems_e500_clrtlb(rtems_e500_tlb_idx key)
660{
661rtems_e500_tlb_idx    k0;
662rtems_interrupt_level lvl;
663
664        /* minimal guard against bad key */
665        if ( key < 0 )
666                return -1;
667
668        if ( (key & E500_SELTLB_1) ) {
669                if ( (key & ~E500_SELTLB_1) > 15 ) {
670                        myprintf(stderr,"Invalid TLB index; TLB1 index must be < 16\n");
671                        return -1;     
672                }
673        } else if ( key > 255 ) {
674                        myprintf(stderr,"Invalid TLB index; TLB0 index must be < 256\n");
675                        return -1;     
676        }
677
678        /* Must not invalidate page 0 which holds vectors, text etc...  */
679        k0 = rtems_e500_ftlb(0, 0);
680        if ( -1 == k0 ) {
681                myprintf(stderr,"tlbivax; something's fishy - I don't find mapping for addr. 0\n");
682                return -1;
683        }
684
685        /* NOTE: we assume PID is ignored, and AS is 0 */
686        if ( k0 == key ) {
687                myprintf(stderr,"Refuse to invalidate page holding addr 0 (always needed)\n");
688                return -1;
689        }
690
691        rtems_interrupt_disable(lvl);
692
693        seltlb(key);
694
695        asm volatile("tlbre");
696
697        /* read old entries */
698        _write_MAS1( _read_MAS1() & ~MAS1_V );
699
700        asm volatile(
701                "       sync            \n"
702                "       isync           \n"
703                "       tlbwe       \n"
704                "       sync        \n"
705                "       isync           \n"
706        );
707
708        /* update cache */
709        if ( E500_SELTLB_1 & key )
710                rtems_e500_tlb_va_cache[ (~E500_SELTLB_1 & key) ].att.v = 0;
711
712        rtems_interrupt_enable(lvl);
713
714        return 0;
715}
Note: See TracBrowser for help on using the repository browser.