source: rtems/bsps/powerpc/haleakala/start/mmu_405.c

Last change on this file was 95d5426c, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 25, 2018 at 8:26:05 AM

bsp/haleakala: Move mmu_405.c to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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