Add simple GDB stub.
[reactos.git] / reactos / lib / ppcmmu / mmuobject.c
1 #include <stdarg.h>
2 #include "ppcmmu/mmu.h"
3 #include "ppcmmu/mmuutil.h"
4 #include "mmuobject.h"
5 #include "helper.h"
6
7 typedef unsigned long ULONG;
8
9 /*
10
11 The MMU Object:
12 0x00300 -- Data miss
13 0x00400 -- Instruction miss
14 0x10000 -- Entry point
15 ... Code
16 0x20000 -- Physical map (PTE + Process Ptr + Address : 16 bytes)
17
18 4096 / 16 bytes = 256 entries per page
19 256 pages = 1Megabyte = 1 page table page
20
21 Setup by freeldr and used to build the kernel map, then used by the kernel
22
23 Calling:
24
25 r3 -- Action
26 r4 .. r6 -- Args
27
28 Actions:
29 00 Init
30 01 Map pages
31 02 erase pages
32 03 set segment vsid
33 04 page miss callback
34 05 inquire page
35 06 unit test
36 07 alloc page
37 08 set memory size
38 09 get first usable page
39 10 alloc vsid
40 11 revoke vsid
41 */
42
43 MmuTrapHandler callback[0x30];
44 typedef struct _MmuFreePage {
45 int page;
46 struct _MmuFreePage *next;
47 } MmuFreePage;
48 typedef struct _MmuFreeTree {
49 struct _MmuFreeTree *next;
50 } MmuFreeTree;
51 typedef struct _MmuVsidTree {
52 ppc_map_t *leaves[256];
53 } MmuVsidTree;
54 typedef struct _MmuVsidInfo {
55 int vsid;
56 struct _MmuVsidInfo *next;
57 MmuVsidTree *tree[256];
58 } MmuVsidInfo;
59 MmuFreePage *FreeList;
60 // Pages are allocated one by one until NextPage == RamSize >> PPC_PAGE_SHIFT
61 // Then we take only from the free list
62 int Clock = 0, TreeAlloc = 0, GdbAttach = 0;
63 paddr_t RamSize, FirstUsablePage, NextPage;
64 MmuVsidTree *NextTreePage = 0;
65 MmuFreeTree *FreeTree;
66 MmuVsidInfo *Segs[16], *VsidHead = 0;
67
68 extern void fmtout(const char *fmt, ...);
69 int ptegreload(ppc_trap_frame_t *frame, vaddr_t addr);
70 void SerialSetUp(int deviceType, void *deviceAddr, int baud);
71 void TakeException(int n, int *tf);
72
73 int _mmumain(int action, void *arg1, void *arg2, void *arg3)
74 {
75 void (*fun)(void *) = arg1;
76 ppc_trap_frame_t *trap_frame = arg1;
77 int ret = 0;
78
79 switch(action)
80 {
81 /* Trap Handlers */
82 case 3:
83 if(!ptegreload(trap_frame, trap_frame->dar))
84 {
85 __asm__("mfmsr 3\n\tori 3,3,0x30\n\tmtmsr 3\n\t");
86 if (!callback[action](action,arg1)) hang(action, arg1);
87 }
88 break;
89 case 4:
90 if(!ptegreload(trap_frame, trap_frame->srr0))
91 {
92 __asm__("mfmsr 3\n\tori 3,3,0x30\n\tmtmsr 3\n\t");
93 if (!callback[action](action,arg1)) hang(action, arg1);
94 }
95 break;
96
97 case 0:
98 case 2:
99 case 5:
100 case 6:
101 case 7:
102 case 8:
103 case 9:
104 case 0xa:
105 if (!callback[action](action,arg1)) hang(action, arg1);
106 break;
107
108 case 0x20:
109 // Single step
110 TakeException(action, arg1);
111 break;
112
113 /* MMU Functions */
114 case 0x100:
115 initme();
116 break;
117 case 0x101:
118 ret = mmuaddpage(arg1, (int)arg2);
119 break;
120 case 0x102:
121 mmudelpage(arg1, (int)arg2);
122 break;
123 case 0x103:
124 mmusetvsid((int)arg1, (int)arg2, (int)arg3);
125 break;
126 case 0x104:
127 ret = (int)callback[(int)arg1];
128 callback[(int)arg1] = (MmuTrapHandler)arg2;
129 break;
130 case 0x105:
131 mmugetpage(arg1, (int)arg2);
132 break;
133 case 0x106:
134 ret = mmunitest();
135 break;
136 case 0x107:
137 __asm__("mfmsr 3\n\t"
138 "ori 3,3,0x30\n\t"
139 "mtmsr 3\n\t"
140 "mtsdr1 %0\n\t"
141 "mr 0,%2\n\t"
142 "mtctr 0\n\t"
143 "mr 3,%1\n\t"
144 "bctrl\n\t"
145 : : "r" (HTABORG), "r" (arg2), "r" (fun));
146 /* BYE ! */
147 break;
148 case 0x108:
149 mmusetramsize((paddr_t)arg1);
150 break;
151 case 0x109:
152 return FirstUsablePage;
153 case 0x10a:
154 mmuallocvsid((int)arg1, (int)arg2);
155 break;
156 case 0x10b:
157 mmufreevsid((int)arg1, (int)arg2);
158 break;
159
160 case 0x200:
161 SerialSetUp((int)arg1, arg2, 9600);
162 break;
163 case 0x201:
164 TakeException((int)arg1, (int *)arg2);
165 break;
166
167 default:
168 while(1);
169 }
170
171 return ret;
172 }
173
174 void outchar(char c)
175 {
176 SetPhysByte(0x800003f8, c);
177 }
178
179 void outstr(const char *str)
180 {
181 while(*str) outchar(*str);
182 }
183
184 void outdig(int dig)
185 {
186 if(dig < 10) outchar(dig + '0');
187 else outchar(dig - 10 + 'A');
188 }
189
190 void outnum(unsigned long num)
191 {
192 int i;
193 for( i = 0; i < 8; i++ )
194 {
195 outdig(num >> 28);
196 num <<= 4;
197 }
198 }
199
200 void fmtout(const char *str, ...)
201 {
202 va_list ap;
203 va_start(ap, str);
204 while(*str)
205 {
206 if(*str == '%')
207 {
208 if(str[1] == '%')
209 {
210 outchar('%');
211 }
212 else if(str[1] == 's')
213 {
214 outstr(va_arg(ap, const char *));
215 }
216 else
217 {
218 outnum(va_arg(ap, int));
219 }
220 str++;
221 }
222 else
223 {
224 outchar(*str);
225 }
226 str++;
227 }
228 va_end(ap);
229 }
230
231 void mmusetramsize(paddr_t ramsize)
232 {
233 ppc_map_t *last_map = &PpcPageTable[PPC_PAGE_NUMBER(ramsize)];
234 if(!RamSize)
235 {
236 RamSize = ramsize;
237 FirstUsablePage = (paddr_t)last_map;
238 NextPage = PPC_PAGE_NUMBER(FirstUsablePage);
239 }
240 }
241
242 int ignore(int trapCode, ppc_trap_frame_t *trap)
243 {
244 return 1;
245 }
246
247 int hang(int trapCode, ppc_trap_frame_t *trap)
248 {
249 if (!GdbAttach)
250 {
251 GdbAttach = 1;
252 SerialSetUp(0, (void *)0x800003f8, 9600);
253 }
254 TakeException(trapCode, (int *)trap);
255 return 1;
256 }
257
258 int fpenable(int trapCode, ppc_trap_frame_t *trap)
259 {
260 /* Turn on FP */
261 trap->srr0 |= 8192;
262 return 1;
263 }
264
265 extern int trap_start[], trap_end[];
266 void copy_trap_handler(int trap)
267 {
268 int i;
269 paddr_t targetArea = trap * 0x100;
270
271 /* Set target addr */
272 trap_end[0] = (int)_mmumain;
273
274 for (i = 0; i <= trap_end - trap_start; i++)
275 {
276 SetPhys(targetArea + (i * sizeof(int)), trap_start[i]);
277 }
278 }
279
280 void initme()
281 {
282 int i;
283
284 for(i = 0; i < HTABSIZ / sizeof(int); i++)
285 {
286 ((int *)HTABORG)[i] = 0;
287 }
288
289 /* Default to hang on unknown exception */
290 for(i = 0; i < 30; i++)
291 {
292 callback[i] = hang;
293 if (i != 1) /* Preserve reset handler */
294 copy_trap_handler(i);
295 }
296
297 /* Floating point exception */
298 callback[8] = fpenable;
299
300 /* Ignore decrementer and EE */
301 callback[9] = ignore;
302 }
303
304 ppc_map_t *allocpage()
305 {
306 MmuFreePage *FreePage = 0;
307
308 if(NextPage < PPC_PAGE_NUMBER(RamSize)) {
309 return &PpcPageTable[NextPage++];
310 } else {
311 FreePage = FreeList;
312 FreeList = FreeList->next;
313 return ((ppc_map_t*)FreePage);
314 }
315 }
316
317 void freepage(ppc_map_t *PagePtr)
318 {
319 MmuFreePage *FreePage = (MmuFreePage*)PagePtr;
320 PagePtr->proc = PagePtr->addr = 0;
321 FreePage->next = FreeList;
322 FreeList = FreePage;
323 }
324
325 MmuVsidTree *allocvsidtree()
326 {
327 if(FreeTree)
328 {
329 MmuVsidTree *result = (MmuVsidTree*)FreeTree;
330 FreeTree = FreeTree->next;
331 return result;
332 }
333 else if(TreeAlloc >= 3 || !NextTreePage)
334 {
335 ppc_map_t *map = allocpage();
336 NextTreePage = (MmuVsidTree*)PPC_PAGE_ADDR((map - PpcPageTable));
337 TreeAlloc = 1;
338 return NextTreePage;
339 }
340 else
341 {
342 return &NextTreePage[TreeAlloc++];
343 }
344 }
345
346 void freevsidtree(MmuVsidTree *tree)
347 {
348 int i;
349 for(i = 0; i < 256; i++)
350 if(tree->leaves[i])
351 freepage(tree->leaves[i]);
352 MmuFreeTree *NextFreeTree = (MmuFreeTree *)tree;
353 NextFreeTree->next = FreeTree;
354 FreeTree = NextFreeTree;
355 }
356
357 void *allocvsid(int vsid)
358 {
359 ppc_map_t *map = allocpage();
360 MmuVsidInfo *info;
361 if(!map) return 0;
362 map->pte.pteh = map->pte.ptel = 0;
363 info = (MmuVsidInfo*)PPC_PAGE_ADDR((map - PpcPageTable));
364 info->vsid = vsid;
365 info->next = VsidHead;
366 VsidHead = info;
367 return info;
368 }
369
370 void mmuallocvsid(int vsid, int mask)
371 {
372 int i;
373 for(i = 0; i < 16; i++)
374 {
375 if(mask & (1 << i))
376 allocvsid((vsid << 4) + i);
377 }
378 }
379
380 MmuVsidInfo *findvsid(int vsid)
381 {
382 MmuVsidInfo *info;
383 for(info = VsidHead; info; info = info->next)
384 {
385 if(info->vsid == vsid) return info;
386 }
387 return 0;
388 }
389
390 void freevsid(int vsid)
391 {
392 int i;
393 MmuVsidInfo *info = findvsid(vsid);
394 if(!info) return;
395 ppc_map_t *map = &PpcPageTable[PPC_PAGE_NUMBER((paddr_t)info)];
396 for(i = 0; i < 256; i++)
397 {
398 if(info->tree[i])
399 freevsidtree(info->tree[i]);
400 }
401 freepage(map);
402 }
403
404 void mmufreevsid(int vsid, int mask)
405 {
406 int i;
407 for(i = 0; i < 16; i++)
408 {
409 if(mask & (1 << i))
410 allocvsid((vsid << 4) + i);
411 }
412 }
413
414 int mmuaddpage(ppc_map_info_t *info, int count)
415 {
416 int i, iva = 0, vsid, phys, virt;
417 int ptehi;
418 int ptelo, vsid_table_hi, vsid_table_lo;
419 ppc_map_t *PagePtr;
420 MmuVsidInfo *VsidInfo;
421 MmuVsidTree *VsidTree;
422
423 for(i = 0; i < count; i++)
424 {
425 virt = info[i].addr;
426 vsid = ((info[i].addr >> 28) & 15) | (info[i].proc << 4);
427 VsidInfo = findvsid(vsid);
428
429 if(!VsidInfo) return -1;
430
431 ptehi = (1 << 31) | (vsid << 7) | ((virt >> 22) & 0x3f);
432
433 if(info[i].phys) {
434 PagePtr = &PpcPageTable[PPC_PAGE_NUMBER(info[i].phys)];
435 } else {
436 PagePtr = allocpage();
437 if(!PagePtr)
438 {
439 return 0;
440 }
441 }
442
443 phys = PPC_PAGE_ADDR((PagePtr - PpcPageTable));
444 ptelo = phys & ~PPC_PAGE_MASK;
445
446 /* Update page data */
447 PagePtr->pte.pteh = ptehi;
448 PagePtr->pte.ptel = ptelo;
449 PagePtr->proc = info[i].proc;
450 PagePtr->addr = virt;
451
452 vsid_table_hi = virt >> 20 & 255;
453 vsid_table_lo = virt >> 12 & 255;
454
455 if(!VsidInfo->tree[vsid_table_hi])
456 VsidInfo->tree[vsid_table_hi] = allocvsidtree();
457 VsidTree = VsidInfo->tree[vsid_table_hi];
458 if(!VsidTree) return 0;
459 VsidTree->leaves[vsid_table_lo] = PagePtr;
460
461 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (iva));
462 }
463 return 1;
464 }
465
466 ppc_pteg_t *PtegFromPage(ppc_map_t *map, int hfun)
467 {
468 if(!map->proc && !map->addr) return 0;
469 return &PpcHashedPTE[PtegNumber(map->addr, hfun)];
470 }
471
472 int PageMatch(vaddr_t addr, ppc_pte_t pte)
473 {
474 int vsid_pte = (pte.pteh >> 7) & 15, api_pte = pte.pteh & 63;
475 return
476 (((addr >> 28) & 15) == vsid_pte) &&
477 (((addr >> 22) & 63) == api_pte);
478 }
479
480 ppc_map_t *mmuvirtmap(vaddr_t addr, int vsid)
481 {
482 int seg = (addr >> 28) & 15;
483 MmuVsidInfo *seginfo = Segs[seg];
484 MmuVsidTree *segtree = 0;
485 if(!seginfo) return 0;
486 segtree = seginfo->tree[(addr >> 20) & 255];
487 if(!segtree) return 0;
488 return segtree->leaves[(addr >> 12) & 255];
489 }
490
491 void mmudelpage(ppc_map_info_t *info, int count)
492 {
493 int i, j, k, ipa;
494 ppc_map_t *PagePtr;
495 ppc_pteg_t *PageEntry;
496 ppc_pte_t ZeroPte = { 0 };
497
498 for(i = 0; i < count; i++)
499 {
500 if (info[i].phys)
501 {
502 ipa = info[i].phys;
503 PagePtr = &PpcPageTable[ipa];
504 info[i].proc = PagePtr->proc;
505 info[i].addr = PagePtr->addr;
506 }
507 else
508 {
509 PagePtr = mmuvirtmap(info[i].proc, info[i].addr);
510 ipa = PPC_PAGE_ADDR(PagePtr - PpcPageTable);
511 }
512
513 for(j = 0; j < 2; j++)
514 {
515 PageEntry = PtegFromPage(PagePtr, j);
516 for(k = 0; k < 8; k++)
517 {
518 if(PageMatch(ipa, PageEntry->block[k]))
519 {
520 if(PageEntry->block[k].ptel & 0x100)
521 info[i].flags |= MMU_PAGE_DIRTY;
522 PageEntry->block[k] = ZeroPte;
523 }
524 }
525 }
526 freepage(PagePtr);
527 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (info[i].addr));
528 }
529 }
530
531 void mmugetpage(ppc_map_info_t *info, int count)
532 {
533 int i;
534 ppc_map_t *PagePtr;
535
536 for( i = 0; i < count; i++ )
537 {
538 if(!info[i].addr && !info[i].proc)
539 {
540 PagePtr = &((ppc_map_t*)PAGETAB)[info[i].phys];
541 info[i].proc = PagePtr->proc;
542 info[i].addr = PagePtr->addr;
543 info[i].flags = MMU_ALL_RW;
544 } else {
545 vaddr_t addr = info[i].addr;
546 int vsid = ((addr >> 28) & 15) | (info[i].proc << 4);
547 PagePtr = mmuvirtmap(info[i].addr, vsid);
548 if(!PagePtr)
549 info[i].phys = 0;
550 else
551 {
552 info[i].phys = PPC_PAGE_ADDR(PagePtr - PpcPageTable);
553 info[i].flags = MMU_ALL_RW; // HACK
554 }
555 }
556 }
557 }
558
559 void mmusetvsid(int start, int end, int vsid)
560 {
561 int i, sr, s_vsid;
562 for(i = start; i < end; i++)
563 {
564 s_vsid = (vsid << 4) | (i & 15);
565 sr = (GetSR(i) & ~PPC_VSID_MASK) | s_vsid;
566 SetSR(i, sr);
567 Segs[i] = findvsid(s_vsid);
568 }
569 }
570
571 int ptegreload(ppc_trap_frame_t *frame, vaddr_t addr)
572 {
573 int hfun = (Clock >> 3) & 1, ptegnum = PtegNumber(addr, hfun);
574 int vsid = GetSR((addr >> 28) & 15) & PPC_VSID_MASK;
575 ppc_map_t *map = mmuvirtmap(addr, vsid);
576 if(!map) return 0;
577 map->pte.pteh = (map->pte.pteh & ~64) | (hfun << 6);
578 PpcHashedPTE[ptegnum].block[Clock & 7] = map->pte;
579 #if 0
580 fmtout("Reloading addr %x (phys %x) at %x[%x] (%x:%x)\r\n",
581 addr, PPC_PAGE_ADDR(map - PpcPageTable), ptegnum, Clock & 15,
582 PpcHashedPTE[ptegnum].block[Clock&7].pteh,
583 PpcHashedPTE[ptegnum].block[Clock&7].ptel);
584 #endif
585 Clock++;
586 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (addr));
587 return 1;
588 }