2 Copyright © 2008-2014, The AROS Development Team. All rights reserved.
7 #include <asm/mpc5200b.h>
9 #include <aros/kernel.h>
10 #include <aros/libcall.h>
14 #include <proto/exec.h>
15 #include <proto/kernel.h>
17 #include "kernel_intern.h"
24 /* Search the MMU hash table for page table entry corresponding to virtual address given */
26 pte_t
*find_pte(uint64_t virt
)
28 pte_t
*ret
= (pte_t
*)0;
35 /* Calculate the hash function */
36 uint32_t hash
= (((virt
>> 12) & 0xffff) ^ (virt
>> 28)) & 0x7ffff;
38 /* what vsid we are looking for? */
39 vsid
= 0x80000000 | ((virt
>> 28) << 7) | ((virt
>> 22) & 0x3f);
41 /* What mask are we using? Depends on the size of MMU hashtable */
42 mask
= ((rdspr(SDR1
) & 0x1ff) << 16) | 0xffc0;
44 /* Get the first group of pte's */
45 pteg
= (pte_t
*)((rdspr(SDR1
) & ~0x1ff) | ((hash
<< 6) & mask
));
47 /* Search the primary group */
50 if (pteg
[i
].vsid
== vsid
)
58 * If the page was not found in primary group, get the second hash, second
59 * vsid and search the secondary group.
63 uint32_t hash2
= (~hash
) & 0x7ffff;
65 pteg
= (pte_t
*)((rdspr(SDR1
) & ~0x1ff) | ((hash2
<< 6) & mask
));
67 /* Search the secondary group */
70 if (pteg
[i
].vsid
== vsid
)
81 uint16_t mmu_protection(KRN_MapAttr flags
)
83 uint16_t ppc_prot
= 2 << 3; /* WIMG = 0010 */
85 if (flags
& MAP_Readable
)
89 if (flags
& MAP_Writable
)
91 ppc_prot
= (ppc_prot
| 2) & ~1;
94 if (flags
& MAP_WriteThrough
)
98 if (flags
& MAP_Guarded
)
102 if (flags
& MAP_CacheInhibit
)
104 ppc_prot
= (ppc_prot
| 4 << 3) & ~ (8 << 3);
107 return ppc_prot
& 0xfff;
110 int mmu_map_page(uint64_t virt
, uint32_t phys
, uint32_t prot
)
112 uint32_t mask
= ((rdspr(SDR1
) & 0x1ff) << 16) | 0xffc0;
118 /* Calculate the hash function */
119 uint32_t hash
= (((uint32_t)(virt
>> 12) & 0xffff) ^ (uint32_t)(virt
>> 28)) & 0x7ffff;
121 pteg
= (pte_t
*)((rdspr(SDR1
) & ~0x1ff) | ((hash
<< 6) & mask
));
123 for (ptenum
= 0; ptenum
< 8; ptenum
++)
125 if (!(pteg
[ptenum
].vsid
& 0x80000000))
134 uint32_t hash2
= (~hash
) & 0x7ffff;
135 pteg
= (pte_t
*)((rdspr(SDR1
) & ~0x1ff) | ((hash2
<< 6) & mask
));
137 for (ptenum
= 0; ptenum
< 8; ptenum
++)
139 if (!(pteg
[ptenum
].vsid
& 0x80000000))
142 local_pte
.vsid
= 0x40;
150 D(bug("[KRN] mmu_map_page(%06x%07x, %08x, %08x)\n", (uint32_t)(virt
>> 28), (uint32_t)(virt
& 0x0fffffff), phys
, prot
));
151 D(bug("[KRN] Run out of free page table entries\n"));
155 local_pte
.vsid
|= ((virt
>> 28) << 7);
156 local_pte
.vsid
|= ((virt
>> 22) & 0x3f);
157 local_pte
.vsid
|= 0x80000000;
158 local_pte
.rpn
= (phys
& ~0xfff) | (prot
& 0xfff);
162 asm volatile("dcbst 0,%0; sync;"::"r"(pte
));
163 asm volatile("tlbie %0"::"r"((uint32_t)virt
));
168 int mmu_map_area(uint64_t virt
, uint32_t phys
, uint32_t length
, uint32_t prot
)
170 bug("[KRN] mmu_map_area(%04x%08x, %08x, %08x, %04x)\n", (uint32_t)(virt
>> 32), (uint32_t)virt
, phys
, length
, prot
);
173 if (!mmu_map_page(virt
, phys
, prot
))
184 void mmu_init(char *mmu_dir
, uint32_t mmu_size
)
188 D(bug("[KRN] Initializing MMU\n"));
189 D(bug("[KRN] Location of MMU tables: %08x-%08x\n", mmu_dir
, mmu_dir
+ mmu_size
- 1));
191 if ((intptr_t)mmu_dir
& (mmu_size
- 1))
193 D(bug("[KRN] WRONG! The MMU dir must be located on mmu length boundary\n"));
198 /* Clear the MMU tables */
199 memset(mmu_dir
, 0, mmu_size
);
201 uint32_t sdr
= (intptr_t)mmu_dir
| ((mmu_size
>> 16) - 1);
203 D(bug("[KRN] SDR1 = %08x\n", sdr
));
207 /* Prepare the segment registers. The proper values for virtual address
208 * are to be determined later */
210 for (i
=0; i
< 16; i
++)
212 asm volatile ("mtsrin %0,%1"::"r"(0x20000000 | i
),"r"(i
<< 28));
215 D(bug("[KRN] Flushing TLB\n"));
216 for (ea
=0x00001000; ea
<= 0x0001f000; ea
+=0x1000)
217 asm volatile("tlbie %0"::"r"(ea
));
221 void __attribute__((noreturn
)) mmu_handler(regs_t
*ctx
, uint8_t exception
, void *self
)
223 struct KernelBase
*KernelBase
= getKernelBase();
224 struct ExecBase
*SysBase
= getSysBase();
226 ctx
->dar
= rdspr(19);
227 ctx
->dsisr
= rdspr(18);
229 /* SysBase access at 4UL? Occurs only with lwz instruction and DAR=4 */
230 if ((exception
== 3) && (ctx
->dar
== 4))
232 uint32_t insn
= *(uint32_t *)ctx
->srr0
;
234 if ((insn
& 0xfc000000) == 0x80000000)
236 int reg
= (insn
& 0x03e00000) >> 21;
238 ctx
->gpr
[reg
] = getSysBase();
241 core_LeaveInterrupt(ctx
);
245 D(bug("[KRN] Exception %d (%s) handler. Context @ %p, SysBase @ %p, KernelBase @ %p\n", exception
, exception
== 3 ? "DSI" : "ISI", ctx
, SysBase
, KernelBase
));
248 struct Task
*t
= FindTask(NULL
);
252 offset
= findNames(ctx
->srr0
, &mod
, &func
);
253 D(bug("[KRN] %s %p (%s)\n", t
->tc_Node
.ln_Type
== NT_TASK
? "Task":"Process", t
, t
->tc_Node
.ln_Name
? t
->tc_Node
.ln_Name
: "--unknown--"));
256 D(bug("[KRN] Crash at byte %d in func %s, module %s\n", offset
, func
, mod
));
258 D(bug("[KRN] Crash at byte %d in module %s\n", offset
, mod
));
260 D(bug("[KRN] SPLower=%08x SPUpper=%08x\n", t
->tc_SPLower
, t
->tc_SPUpper
));
261 D(bug("[KRN] Stack usage: %d bytes (%d %%)\n", t
->tc_SPUpper
- ctx
->gpr
[1],
262 100 * ((uintptr_t)t
->tc_SPUpper
- ctx
->gpr
[1]) / ((uintptr_t)t
->tc_SPUpper
- (uintptr_t)t
->tc_SPLower
)));
264 if (ctx
->gpr
[1] >= t
->tc_SPLower
&& ctx
->gpr
[1] < t
->tc_SPUpper
)
265 D(bug("[KRN] Stack in bounds\n"));
267 D(bug("[KRN] Stack exceeded the allowed size!\n"));
270 D(bug("[KRN] Attempt to %s address %08x.\n", ctx
->dsisr
& 0x02000000 ? "write to":"read from", ctx
->dar
));
272 D(bug("[KRN] SRR0=%08x, SRR1=%08x\n",ctx
->srr0
, ctx
->srr1
));
273 D(bug("[KRN] CTR=%08x LR=%08x XER=%08x CCR=%08x\n", ctx
->ctr
, ctx
->lr
, ctx
->xer
, ctx
->ccr
));
274 D(bug("[KRN] DAR=%08x DSISR=%08x\n", ctx
->dar
, ctx
->dsisr
));
276 D(bug("[KRN] HASH1=%08x HASH2=%08x IMISS=%08x DMISS=%08x ICMP=%08x DCMP=%08x\n",
277 rdspr(978), rdspr(979), rdspr(980), rdspr(976), rdspr(981), rdspr(977)));
279 D(bug("[KRN] SPRG0=%08x SPRG1=%08x SPRG2=%08x SPRG3=%08x SPRG4=%08x SPRG5=%08x\n",
280 rdspr(SPRG0
),rdspr(SPRG1
),rdspr(SPRG2
),rdspr(SPRG3
),rdspr(SPRG4
),rdspr(SPRG5
)));
282 D(bug("[KRN] GPR00=%08x GPR01=%08x GPR02=%08x GPR03=%08x\n",
283 ctx
->gpr
[0],ctx
->gpr
[1],ctx
->gpr
[2],ctx
->gpr
[3]));
284 D(bug("[KRN] GPR04=%08x GPR05=%08x GPR06=%08x GPR07=%08x\n",
285 ctx
->gpr
[4],ctx
->gpr
[5],ctx
->gpr
[6],ctx
->gpr
[7]));
286 D(bug("[KRN] GPR08=%08x GPR09=%08x GPR10=%08x GPR11=%08x\n",
287 ctx
->gpr
[8],ctx
->gpr
[9],ctx
->gpr
[10],ctx
->gpr
[11]));
288 D(bug("[KRN] GPR12=%08x GPR13=%08x GPR14=%08x GPR15=%08x\n",
289 ctx
->gpr
[12],ctx
->gpr
[13],ctx
->gpr
[14],ctx
->gpr
[15]));
291 D(bug("[KRN] GPR16=%08x GPR17=%08x GPR18=%08x GPR19=%08x\n",
292 ctx
->gpr
[16],ctx
->gpr
[17],ctx
->gpr
[18],ctx
->gpr
[19]));
293 D(bug("[KRN] GPR20=%08x GPR21=%08x GPR22=%08x GPR23=%08x\n",
294 ctx
->gpr
[20],ctx
->gpr
[21],ctx
->gpr
[22],ctx
->gpr
[23]));
295 D(bug("[KRN] GPR24=%08x GPR25=%08x GPR26=%08x GPR27=%08x\n",
296 ctx
->gpr
[24],ctx
->gpr
[25],ctx
->gpr
[26],ctx
->gpr
[27]));
297 D(bug("[KRN] GPR28=%08x GPR29=%08x GPR30=%08x GPR31=%08x\n",
298 ctx
->gpr
[28],ctx
->gpr
[29],ctx
->gpr
[30],ctx
->gpr
[31]));
301 D(bug("[KRN] Hash1 dump:\n[KRN] "));
302 uint32_t *hash
= (uint32_t)rdspr(978);
303 for (i
=0; i
< 8; i
++)
305 D(bug("%08x.%08x ", hash
[0], hash
[1]));
310 D(bug("\n[KRN] Hash2 dump:\n[KRN] "));
311 hash
= (uint32_t)rdspr(979);
312 for (i
=0; i
< 8; i
++)
314 D(bug("%08x.%08x ", hash
[0], hash
[1]));
320 D(bug("[KRN] Instruction dump:\n"));
321 ULONG
*p
= (ULONG
*)ctx
->srr0
;
322 for (i
=0; i
< 8; i
++)
324 if (find_pte((uint32_t)&p
[i
]))
325 D(bug("[KRN] %08x: %08x\n", &p
[i
], p
[i
]));
327 D(bug("[KRN] %08x: ?\n", &p
[i
]));
330 D(bug("[KRN] Backtrace:\n"));
331 uint32_t *sp
= ctx
->gpr
[1];
335 sp
= (uint32_t *)sp
[0];
338 offset
= findNames(sp
[1], &mod
, &func
);
341 D(bug("[KRN] %08x: byte %d in func %s, module %s\n", sp
[1], offset
, func
, mod
));
343 D(bug("[KRN] %08x: byte %d in module %s\n", sp
[1], offset
, mod
));
345 D(bug("[KRN] %08x\n", sp
[1]));
350 struct Task
*dead
= SysBase
->ThisTask
;
352 SysBase
->ThisTask
= NULL
;
353 KernelBase
->kb_LastDeadTask
= dead
;
355 Enqueue(&KernelBase
->kb_DeadTasks
, dead
);
361 D(bug("[KRN] **UNHANDLED EXCEPTION** stopping here...\n"));
364 wrmsr(rdmsr() | MSR_POW
);
368 AROS_LH3(void, KrnSetProtection
,
369 AROS_LHA(void *, address
, A0
),
370 AROS_LHA(uint32_t, length
, D0
),
371 AROS_LHA(KRN_MapAttr
, flags
, D1
),
372 struct KernelBase
*, KernelBase
, 21, Kernel
)
376 uint32_t ppc_prot
= mmu_protection(flags
);
377 uintptr_t virt
= (uintptr_t)address
;
380 D(bug("[KRN] KrnSetProtection(%08x, %08x, %04x)\n", virt
, virt
+ length
- 1, ppc_prot
));
383 length
= (length
+ 4095) & ~4095;
389 pte
= find_pte(virt
);
393 pte
->rpn
= (pte
->rpn
& 0xfffff000) | ppc_prot
;
404 AROS_LH4(int, KrnMapGlobal
,
405 AROS_LHA(void *, virtual, A0
),
406 AROS_LHA(void *, physical
, A1
),
407 AROS_LHA(uint32_t, length
, D0
),
408 AROS_LHA(KRN_MapAttr
, flags
, D1
),
409 struct KernelBase
*, KernelBase
, 16, Kernel
)
415 uint32_t ppc_prot
= mmu_protection(flags
);
417 D(bug("[KRN] KrnMapGlobal(%08x->%08x %08x %04x)\n", virtual, physical
, length
, flags
));
420 retval
= mmu_map_area((uint64_t)virtual & 0xffffffff, physical
, length
, ppc_prot
);
428 AROS_LH2(int, KrnUnmapGlobal
,
429 AROS_LHA(void *, virtual, A0
),
430 AROS_LHA(uint32_t, length
, D0
),
431 struct KernelBase
*, KernelBase
, 17, Kernel
)
437 uintptr_t virt
= (uintptr_t)virtual;
439 length
= (length
+ 4095) & ~4095;
444 pte_t
*pte
= find_pte(virt
);
456 uintptr_t virt2phys(uintptr_t virt
)
458 uintptr_t phys
= 0xffffffff;
459 pte_t
*pte
= find_pte(virt
);
463 phys
= pte
->rpn
& ~0xfff;
464 phys
|= virt
& 0xfff;
470 AROS_LH1(void *, KrnVirtualToPhysical
,
471 AROS_LHA(void *, virtual, A0
),
472 struct KernelBase
*, KernelBase
, 20, Kernel
)
476 uintptr_t virt
= (uintptr_t)virtual;
478 uint32_t msr
= goSuper();
480 phys
= virt2phys(virt
);
494 /* MMU exception handlers follow the G2 core manual */
495 static void __attribute__((used
)) __exception_template()
512 * Instruction TB miss flow
516 * srr0 -> address of instruction that missed
517 * srr1 -> 0:3=cr0 4=lru way bit 16:31 = saved MSR
519 * iMiss -> ea that missed
520 * iCmp -> the compare value for the va that missed
521 * hash1 -> pointer to first hash pteg
522 * hash2 -> pointer to second hash pteg
526 * r0 is saved counter
528 * r2 is pointer to pteg
529 * r3 is current compare value
531 asm volatile(".align 8; .globl __vector_imiss; .type __vector_imiss,@function\n"
533 " mfspr %r2,hash1 \n"
537 " addi %r2,%r2,-8 \n"
539 "im1: lwzu %r1,8(%r2) \n"
542 " bne instrSecHash\n"
544 " andi. %r3,%r1,8 \n"
547 " mfspr %r0,iMiss \n"
551 " ori %r1,%r1,0x100 \n"
554 " stb %r1,+6(%r2) \n"
558 " andi. %r1,%r3,0x0040 \n"
560 " mfspr %r2,hash2 \n"
561 " ori %r3,%r3,0x0040 \n"
563 " addi %r2,%r2,-8 \n"
567 " mfspr %r3, srr1 \n"
568 " andi. %r2,%r3,0xffff \n"
569 " addis %r2,%r2,0x0800 \n"
572 " mfspr %r3, srr1 \n"
573 " andi. %r2,%r3,0xffff\n"
574 " addis %r2,%r2,0x4000\n"
579 " xoris %r0,%r0, 0x8002\n"
590 * srr0 -> address of instruction that caused data tlb miss
591 * srr1 -> 0:3=cr0 4=lru way bit 5=1 if store 16:31 = saved MSR
593 * dMiss -> ea that missed
594 * dCmp -> the compare value for the va that missed
595 * hash1 -> pointer to first hash pteg
596 * hash2 -> pointer to second hash pteg
600 * r0 is saved counter
602 * r2 is pointer to pteg
603 * r3 is current compare value
605 asm volatile(".align 8; .globl __vector_dmiss; .type __vector_dmiss,@function\n"
607 " mfspr %r2, hash1 \n"
610 " mfspr %r3, dCmp \n"
611 " addi %r2, %r2, -8\n"
613 "dm1: lwzu %r1, 8(%r2) \n"
614 " cmp c0, %r1, %r3\n"
616 " bne dataSecHash \n"
619 " mfspr %r0, dMiss \n"
620 " mfspr %r3, srr1 \n"
621 " mtcrf 0x80, %r3 \n"
623 " ori %r1, %r1, 0x100\n"
624 " srwi %r1, %r1, 8 \n"
626 " stb %r1, +6(%r2)\n"
630 " andi. %r1, %r3, 0x0040\n"
632 " mfspr %r2, hash2 \n"
633 " ori %r3, %r3, 0x0040\n"
635 " addi %r2, %r2, -8\n"
640 asm volatile(".align 8; .globl __vector_dmissw; .type __vector_dmiss,@function\n"
642 " mfspr %r2, hash1 \n"
645 " mfspr %r3, dCmp \n"
646 " addi %r2, %r2, -8\n"
648 "ceq1: lwzu %r1, 8(%r2) \n"
649 " cmp c0, %r1, %r3\n"
651 " bne cEq0SecHash \n"
653 " andi. %r3,%r1,0x80\n"
654 " beq cEq0ChkProt \n"
656 " mfspr %r0, dMiss \n"
657 " mfspr %r3, srr1 \n"
658 " mtcrf 0x80, %r3 \n"
664 " andi. %r1, %r3, 0x0040\n"
666 " mfspr %r2, hash2 \n"
667 " ori %r3, %r3, 0x0040\n"
669 " addi %r2, %r2, -8\n"
673 " rlwinm. %r3,%r1,30,0,1\n"
675 " andi. %r3,%r1,1 \n"
678 "chk0: mfspr %r3,srr1 \n"
679 " andis. %r3,%r3,0x0008\n"
683 "chk2: ori %r1, %r1, 0x180\n"
684 " sth %r1, 6(%r2) \n"
688 " mfspr %r3, srr1 \n"
689 " rlwinm %r1, %r3, 9,6,6 \n"
690 " addis %r1, %r1, 0x4000 \n"
694 " mfspr %r3, srr1 \n"
695 " rlwinm %r1, %r3, 9,6,6 \n"
696 " addis %r1, %r1, 0x0800 \n"
700 " andi. %r2, %r3, 0xffff \n"
701 " mtspr srr1, %r2 \n"
702 " mtspr dsisr, %r1 \n"
703 " mfspr %r1, dMiss \n"
704 " rlwinm. %r2,%r2,0,31,31 \n"
706 " xor %r1,%r1,0x07 \n"
711 " xoris %r0, %r0, 0x2 \n"
712 " mtcrf 0x80, %r3 \n"
718 asm volatile(".align 8;");