source: rtems/c/src/lib/libbsp/powerpc/haleakala/mmu/mmu_405.c @ 502609c8

4.115
Last change on this file since 502609c8 was 502609c8, checked in by Nigel Spon <nigel@…>, on 11/21/14 at 17:15:22

powerpc/haleakala: Add network driver

close 1405

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 *  Simple interface to the PowerPC 405 MMU
3 *
4 *   Michael Hamel ADInstruments 2008
5 *
6  */
7
8
9#include <bsp.h>
10#include <libcpu/powerpc-utility.h>
11#include "mmu_405.h"
12
13/* #define qLogTLB */
14/* #define qLogTLBDetails */
15
16
17/*--------------------------------- TLB handling ------------------------------------- */
18/* The following are in assembler in mmu_405asm.S  */
19extern  void MMU_GetTLBEntry(uint8_t index, uint32_t* tagword, uint32_t* dataword, uint8_t* pid);
20extern  void MMU_SetTLBEntry(uint8_t index, uint32_t hiword, uint32_t loword, uint8_t pid);
21extern  void MMU_ClearTLBs();
22extern  int16_t MMU_FindTLBEntry(uint32_t address);
23
24
25enum { kNTLBs = 64 };           /* for 403GCX and 405 */
26
27static bool             sFreeTLBs[kNTLBs];
28static uint8_t  sLastIndex = 0;
29static int              sNInUse = 0;
30
31static void MMUFault(const char* what)
32/* Used for all setup faults; these can't really be ignored */
33{
34        printk("\n>>>MMU fatal error %s\n",what);
35        rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
36}
37
38static uint8_t AllocTLB()
39{
40        uint8_t index;
41       
42        index = sLastIndex;
43        do {
44                index++;
45                if (index == kNTLBs)
46                        index = 0;
47                if (index == sLastIndex)
48                        MMUFault("TLB table full");
49        } while (! sFreeTLBs[index]);
50        sFreeTLBs[index] = false;
51        sLastIndex = index;
52        sNInUse++;
53        return index;
54}
55
56static void FreeTLB(uint8_t index)
57{
58        MMU_SetTLBEntry(index,0,0,0);
59        sFreeTLBs[index] = true;
60        sLastIndex = index-1;
61        sNInUse--;
62}
63
64
65/*---------------------------- MMU operations ---------------------------------- */
66
67int DataMissException(BSP_Exception_frame *f, unsigned int vector);
68int InstructionMissException(BSP_Exception_frame *f, unsigned int vector);
69int InstructionFetchException(BSP_Exception_frame *f, unsigned int vector);
70
71void
72mmu_initialise()
73/* Clear the TLBs and set up exception handlers for the MMU miss handlers */
74{
75        int i;
76       
77        MMU_ClearTLBs();
78        for (i=0; i<kNTLBs; i++) {
79                sFreeTLBs[i] = true;
80                MMU_SetTLBEntry(i,0,0,0xFF);
81        }
82        ppc_exc_set_handler(ASM_ISI_VECTOR ,InstructionFetchException);
83        ppc_exc_set_handler(ASM_BOOKE_ITLBMISS_VECTOR ,DataMissException);
84        ppc_exc_set_handler(ASM_BOOKE_DTLBMISS_VECTOR ,InstructionMissException);
85}
86
87static void
88MakeTLBEntries(uint32_t startAt, uint32_t nBytes, bool EX, bool WR, bool I, uint8_t PID)
89{
90        uint32_t mask, options, tagWord, dataWord;
91        uint8_t  index, sizeCode, pid;
92       
93        if ((startAt & 0x3FF) != 0)
94                MMUFault("TLB entry not on 1K boundary");
95        if ((nBytes & 0x3FF) != 0)
96                MMUFault("TLB size not on 1K boundary");
97               
98        options = 0;
99        if (EX) options += 0x200;
100        if (WR) options += 0x100;
101        if (I) options += 5;
102       
103        #ifdef qLogTLB
104                printk("TLB: make entries for $%X bytes from $%X..$%X PID %d",nBytes, startAt, startAt+nBytes-1, PID);
105                if (EX) printk(" EX");
106                if (WR) printk(" WR");
107                if (I) printk(" I");
108                printk("\n");
109        #endif
110       
111        while (nBytes > 0) {
112                /* Find the largest block we can base on this address */
113                mask = 0x3FF;
114                sizeCode = 0;
115                while (mask < nBytes && ((startAt & mask)==0) && sizeCode < 8) {
116                        mask = (mask<<2) + 3;
117                        sizeCode++;
118                }
119                mask >>= 2;
120                sizeCode--;
121               
122                /* Make a TLB entry describing this, ZSEL=0 */
123                tagWord = startAt | (sizeCode<<7) | 0x40;
124                dataWord = startAt | options;
125                index = AllocTLB();
126                MMU_SetTLBEntry( index , tagWord, dataWord, PID);
127               
128                {
129                        /* Paranoia: check that we can read that back... */
130                        uint8_t tdex, oldpid;
131                       
132                        oldpid = mmu_current_processID();
133                        mmu_set_processID(PID);
134                        tdex = MMU_FindTLBEntry(startAt);
135                        mmu_set_processID(oldpid);
136                       
137                        if (tdex != index) {
138                                printk(" Add TLB %d: At %X for $%X sizecode %d tagWord $%X  ",index, startAt, mask+1,sizeCode,tagWord);
139                                printk(" -- find failed, %d/%d!\n",tdex,index);
140                                MMU_GetTLBEntry(index, &tagWord, &dataWord, &pid);
141                                printk(" -- reads back $%X : $%X, PID %d\n",tagWord,dataWord,pid);
142                        } else {
143                                #ifdef qLogTLBDetails
144                                printk(" Add TLB %d: At %X for $%X sizecode %d tagWord $%X\n",index, startAt, mask+1,sizeCode,tagWord);
145                                #endif
146                        }
147                }
148       
149                /* Subtract block from startAddr and nBytes */
150                mask++;         /* Convert to a byte count */
151                startAt += mask;
152                nBytes -= mask;
153        }
154        #ifdef qLogTLB
155                printk(" %d in use\n",sNInUse);
156        #endif
157}
158
159void
160mmu_remove_space(uint32_t startAt, uint32_t endAt)
161{
162        int16_t index;
163        int32_t size;
164        uint32_t tagword, dataword, nBytes;
165        uint8_t  pid, sCode;
166       
167        nBytes = endAt - startAt;
168       
169        #ifdef qLogTLB
170        printk("TLB: delete entries for $%X bytes from $%X\n",nBytes,startAt);
171        #endif
172       
173        while (nBytes > 0) {
174                index = MMU_FindTLBEntry( (uint32_t)startAt );
175                size = 1024;
176                if (index >= 0) {
177                        MMU_GetTLBEntry(index, &tagword, &dataword, &pid);
178                        if ((tagword & 0x40) == 0)
179                                MMUFault("Undefine failed: redundant entries?");
180                        if ((tagword & 0xFFFFFC00) != (uint32_t)startAt)
181                                MMUFault("Undefine not on TLB boundary");
182                        FreeTLB(index);
183                        sCode = (tagword >> 7) & 7;
184                        while (sCode > 0) {
185                                size <<= 2;
186                                sCode--;
187                        }
188                        #ifdef qLogTLBDetails
189                        printk(" Free TLB %d: At %X for $%X\n",index, startAt, size);
190                        #endif
191                }
192                startAt += size;
193                nBytes -= size;
194        }
195}
196
197void
198mmu_add_space(uint32_t startAddr, uint32_t endAddr, MMUAccessType permissions, uint8_t processID)
199/* Convert accesstype to write-enable, executable, and cache-inhibit bits */
200{
201        bool EX, WR, I;
202       
203        EX = false;
204        WR = false;
205        I = false;
206        switch (permissions) {
207                case executable                 : EX = true;  break;
208                case readOnlyData               : break;
209                case readOnlyNoCache    : I = true; break;
210                case readWriteData              : WR = true; break;
211                case readWriteNoCache   : WR = true; I= true; break;
212                case readWriteExecutable: WR = true; EX = true; break;
213        }
214        MakeTLBEntries( (uint32_t)startAddr, (uint32_t)(endAddr-startAddr+1), EX, WR, I, processID);
215}
216
217int
218mmu_get_tlb_count()
219{
220        return sNInUse;
221}
222
223/*---------------------------- CPU process ID handling ----------------------------------
224 * Really dumb system where we just hand out sequential numbers and eventually fail
225 * As long as we only use 8-9 processes this isn't a problem */
226
227static uint8_t sNextPID = 1;
228
229#define SPR_PID         0x3B1
230
231uint8_t mmu_new_processID()
232{
233        return sNextPID++;
234}
235
236void mmu_free_processID(uint8_t freeThis)
237{
238}
239
240uint8_t mmu_current_processID()
241{
242        return PPC_SPECIAL_PURPOSE_REGISTER(SPR_PID);
243}
244
245uint8_t mmu_set_processID(uint8_t newID)
246{
247        uint8_t prev = mmu_current_processID();
248        PPC_SET_SPECIAL_PURPOSE_REGISTER(SPR_PID,newID);
249        return prev;
250}
251
252
253/* ------------------ Fault handlers ------------------ */
254
255#define SPR_ESR         0x3D4
256#define SPR_DEAR        0x3D5
257
258enum { kESR_DST = 0x00800000 };
259
260int DataMissException(BSP_Exception_frame *f, unsigned int vector)
261{
262        uint32_t addr, excSyn;
263       
264        addr = PPC_SPECIAL_PURPOSE_REGISTER(SPR_DEAR);
265        excSyn  = PPC_SPECIAL_PURPOSE_REGISTER(SPR_ESR);
266        if (excSyn & kESR_DST) printk("\n---Data write to $%X attempted at $%X\n",addr,f->EXC_SRR0);
267                                          else printk("\n---Data read from $%X attempted at $%X\n",addr,f->EXC_SRR0);
268        return -1;
269}
270
271int InstructionMissException(BSP_Exception_frame *f, unsigned int vector)
272{
273        printk("\n---Instruction fetch attempted from $%X, no TLB exists\n",f->EXC_SRR0);
274        return -1;
275}
276
277int InstructionFetchException(BSP_Exception_frame *f, unsigned int vector)
278{
279        printk("\n---Instruction fetch attempted from $%X, TLB is no-execute\n",f->EXC_SRR0);
280        return -1;
281}
Note: See TracBrowser for help on using the repository browser.