arch/m68k-amiga: Add MMU entry for CD32 Akiko memory range
[AROS.git] / arch / m68k-amiga / boot / mmu.c
blob7354641343e76a54b117e7557d49460e706aea36
2 #define DEBUG 1
3 #include <aros/debug.h>
4 #include <exec/types.h>
5 #include <exec/resident.h>
6 #include <proto/exec.h>
7 #include <proto/kernel.h>
8 #include <proto/expansion.h>
9 #include <proto/utility.h>
10 #include <libraries/configvars.h>
11 #include <hardware/cpu/memory.h>
13 #include "exec_intern.h"
14 #undef KernelBase
16 #define FASTREMAP 1
18 #define _STR(A) #A
19 #define STR(A) _STR(A)
21 #define NAME "mmu"
22 #define VERSION 41
23 #define REVISION 1
25 static AROS_UFP3 (APTR, Init,
26 AROS_UFPA(struct Library *, lh, D0),
27 AROS_UFPA(BPTR, segList, A0),
28 AROS_UFPA(struct ExecBase *, sysBase, A6));
30 static const TEXT name_string[] = NAME;
31 static const TEXT version_string[] =
32 NAME " " STR(VERSION) "." STR(REVISION) "\n";
34 extern void mmu_end(void);
36 const struct Resident rom_tag =
38 RTC_MATCHWORD,
39 (struct Resident *)&rom_tag,
40 (APTR)&mmu_end,
41 RTF_COLDSTART,
42 VERSION,
43 NT_UNKNOWN,
44 100,
45 (STRPTR)name_string,
46 (STRPTR)version_string,
47 (APTR)Init
50 void enable_mmu(void *kb);
51 void debug_mmu(void *kb);
52 extern BOOL init_mmu(void *kb);
54 extern BYTE _rom_start;
55 extern BYTE _rom_end;
56 extern BYTE _ext_start;
57 extern BYTE _ext_end;
59 static void mmuprotect(void *KernelBase, ULONG addr, ULONG size)
61 KrnSetProtection((void*)addr, size, MAP_Readable | MAP_Executable);
63 static void mmuram(void *KernelBase, ULONG addr, ULONG size)
65 KrnSetProtection((void*)addr, size, MAP_Readable | MAP_Writable | MAP_Executable);
67 static void mmuchipram(void *KernelBase, ULONG addr, ULONG size)
69 KrnSetProtection((void*)addr, size, MAP_Readable | MAP_Writable | MAP_Executable | MAP_CacheInhibit);
71 static void mmuio(void *KernelBase, ULONG addr, ULONG size)
73 KrnSetProtection((void*)addr, size, MAP_Readable | MAP_Writable | MAP_CacheInhibit);
76 static APTR AllocPagesAligned(ULONG pages)
78 APTR ret;
79 ret = AllocMem((pages + 1) * PAGE_SIZE, MEMF_CLEAR | MEMF_FAST | MEMF_REVERSE);
80 if (ret == NULL)
81 return NULL;
82 Forbid();
83 FreeMem(ret, (pages + 1) * PAGE_SIZE);
84 ret = AllocAbs((pages * PAGE_SIZE + PAGE_SIZE - 1) & PAGE_MASK, (APTR)((((ULONG)ret) + PAGE_SIZE - 1) & PAGE_MASK));
85 Permit();
86 return ret;
89 static void swapvbr(APTR vbr)
91 asm volatile (
92 ".chip 68010\n"
93 "move.l %0,%%d0\n"
94 "move.l 4.w,%%a6\n"
95 "lea newvbr(%%pc),%%a5\n"
96 "jsr -0x1e(%%a6)\n"
97 "bra.s 0f\n"
98 "newvbr:\n"
99 "movec %%d0,%%vbr\n"
100 "rte\n"
101 "0:\n"
102 : : "m" (vbr) : "d0", "d1", "a5", "a6");
105 static BOOL ISA3000(void)
107 if (!(SysBase->AttnFlags & AFF_68030))
108 return FALSE;
109 if (SysBase->AttnFlags & AFF_68040)
110 return FALSE;
111 if (ReadGayle())
112 return FALSE;
113 /* We should check for RAMSEY.. Later.. */
114 /* 0x07000000 - 0x07ffffff is A3000-only RAM region */
115 return TypeOfMem((APTR)0x07ff0000) != 0;
118 static void mmuprotectregion(void *KernelBase, const UBYTE *name, APTR addr, ULONG size, ULONG flags)
120 ULONG allocsize = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
121 KrnSetProtection(addr, allocsize, 0);
122 if (FASTREMAP && TypeOfMem(addr) & MEMF_CHIP) {
123 APTR newmem = AllocPagesAligned(allocsize / PAGE_SIZE);
124 if (newmem) {
125 CopyMem(addr, newmem, size);
126 D(bug("Remapped %d byte Chip region to Fast, %p - %p -> %p - %p (%s), flags %08x\n",
127 size, addr, addr + size - 1, newmem, newmem + size - 1, name, flags));
128 KrnMapGlobal(addr, newmem, allocsize, flags);
129 return;
132 D(bug("Protected %d byte region %p - %p (%s) using flags %08x\n", size, addr, addr + size - 1, name, flags));
133 KrnSetProtection(addr, allocsize, flags);
136 /* MMU protect ArosBootStrap loaded ROM modules */
137 static void mmuprotectextrom(void *KernelBase)
139 struct MemList *mlist = (struct MemList*)PrivExecBase(SysBase)->PlatformData.ep_KickMemPtr;
140 UWORD i;
142 while (mlist) {
143 for (i = 0; i < mlist->ml_NumEntries; i++) {
144 IPTR *list = SysBase->ResModules;
145 while (list && *list)
147 APTR ptr;
148 struct Resident *res;
149 if (*list & RESLIST_NEXT) {
150 list = (IPTR *)(*list & ~RESLIST_NEXT);
151 continue;
153 ptr = (APTR)*list++;
154 res = (struct Resident *)ptr;
155 if (res->rt_Flags & (1 << 5)) {
156 if (ptr >= mlist->ml_ME[i].me_Addr && ptr < mlist->ml_ME[i].me_Addr + mlist->ml_ME[i].me_Length) {
157 mmuprotectregion(KernelBase, "ROM", mlist->ml_ME[i].me_Addr, mlist->ml_ME[i].me_Length, MAP_Readable | MAP_Executable);
158 break;
163 mlist = (struct MemList*)mlist->ml_Node.ln_Succ;
167 #define MAX_HEADERS 100
169 static AROS_UFH3 (APTR, Init,
170 AROS_UFHA(struct Library *, lh, D0),
171 AROS_UFHA(BPTR, segList, A0),
172 AROS_UFHA(struct ExecBase *, SysBase, A6)
175 AROS_USERFUNC_INIT
177 void *KernelBase;
178 void *ExpansionBase;
179 struct ConfigDev *cd;
180 ULONG addr, size;
181 ULONG *memheaders;
182 struct MemHeader *mh;
183 UWORD i, cnt;
184 char *args;
185 BOOL ZeroPageInvalid = FALSE, ZeroPageProtect = FALSE;
186 BOOL usemmu = FALSE;
187 UBYTE *vbrpage;
188 ULONG *zero = (ULONG*)0;
190 if (!(SysBase->AttnFlags & AFF_68020))
191 return NULL;
193 KernelBase = OpenResource("kernel.resource");
194 if (!KernelBase)
195 return NULL;
197 /* Parse some arguments from command line */
198 args = (char *)LibGetTagData(KRN_CmdLine, 0, KrnGetBootInfo());
199 if (args) {
200 if (strstr(args, "nommu")) {
201 return NULL;
202 } else if (strstr(args, "debugmmu")) {
203 usemmu = TRUE;
204 ZeroPageInvalid = TRUE;
205 } else if (strstr(args, "pmmu")) {
206 usemmu = TRUE;
207 ZeroPageProtect = TRUE;
208 } else if (strstr(args, "mmu")) {
209 usemmu = TRUE;
213 /* if 68030 A3000 = use MMU, we are guaranteed to have full 68030 */
214 if (!usemmu && ISA3000())
215 usemmu = TRUE;
217 /* 68030/68851: Only enable if mmu commandline detected. */
218 if (!(SysBase->AttnFlags & AFF_68040) && !usemmu)
219 return FALSE;
221 if (!init_mmu(KernelBase)) {
222 D(bug("MMU initialization failed\n"));
223 return NULL;
226 D(bug("Initializing MMU setup\n"));
228 Disable();
230 vbrpage = AllocPagesAligned(1);
231 if (vbrpage) {
232 /* Move VBR to Fast RAM */
233 CopyMem(zero, vbrpage, PAGE_SIZE);
234 swapvbr(vbrpage);
235 D(bug("VBR %p\n", vbrpage));
236 if (ZeroPageInvalid || ZeroPageProtect) {
237 /* Corrupt original zero page vectors, makes bad programs crash faster if we don't
238 * want MMU special zero page handling */
239 for (i = 0; i < 64; i++) {
240 if (i != 1)
241 zero[i] = 0xdeadf00d;
246 /* RAM */
247 memheaders = AllocVec(sizeof(ULONG) * 2 * MAX_HEADERS, MEMF_PUBLIC);
248 if (!memheaders)
249 return NULL;
250 Forbid();
251 cnt = 0;
252 mh = (struct MemHeader*)SysBase->MemList.lh_Head;
253 while (mh->mh_Node.ln_Succ && cnt < MAX_HEADERS) {
254 memheaders[cnt * 2 + 0] = (ULONG)mh->mh_Lower;
255 memheaders[cnt * 2 + 1] = (ULONG)mh->mh_Upper;
256 cnt++;
257 mh = (struct MemHeader*)(mh->mh_Node.ln_Succ);
259 Permit();
260 for (i = 0; i < cnt; i++) {
261 ULONG tm;
262 addr = memheaders[i * 2 + 0];
263 addr &= PAGE_MASK;
264 size = memheaders[i * 2 + 1] - addr;
265 size += PAGE_SIZE - 1;
266 size &= PAGE_MASK;
267 tm = TypeOfMem((void*)(addr + 2 * PAGE_SIZE));
268 if (tm & MEMF_CHIP)
269 mmuchipram(KernelBase, addr, size);
270 else if (tm & MEMF_FAST)
271 mmuram(KernelBase, addr, size);
273 FreeVec(memheaders);
274 if (ReadGayle()) {
275 /* PCMCIA regions */
276 mmuram(KernelBase, 0x00600000, 0x00400000);
277 mmuio(KernelBase, 0x00a00000, 0x00050000);
280 if (ZeroPageInvalid) {
281 /* Mark "zero page" invalid, MMU support handles ExecBase fetches transparently.
282 * Special bus error handler checks if access was LONG READ from address 4.
284 KrnSetProtection(0, PAGE_SIZE, 0);
285 } else if (ZeroPageProtect) {
286 /* Remap zero page to Fast RAM, faster SysBase access */
287 mmuprotectregion(KernelBase, "ZeroPage", 0, PAGE_SIZE, MAP_Readable);
288 } else {
289 /* No special protection, cacheable */
290 KrnSetProtection(0, PAGE_SIZE, MAP_Readable | MAP_Writable);
292 /* Protect Supervisor stack if MMU debugging mode */
293 mmuprotectregion(KernelBase, "SS_Stack", SysBase->SysStkLower, SysBase->SysStkUpper - SysBase->SysStkLower,
294 MAP_Readable | MAP_Writable | ((ZeroPageInvalid || ZeroPageProtect) ? MAP_Supervisor : 0));
296 /* Expansion IO devices */
297 ExpansionBase = TaggedOpenLibrary(TAGGEDOPEN_EXPANSION);
298 cd = NULL;
299 while ((cd = FindConfigDev(cd, -1, -1))) {
300 if (cd->cd_Rom.er_Type & ERTF_MEMLIST)
301 continue;
302 /* Mark all non-RAM (IO) regions as noncacheabled */
303 mmuio(KernelBase, (ULONG)cd->cd_BoardAddr, cd->cd_BoardSize);
305 CloseLibrary(ExpansionBase);
307 /* Some boards may use this as an IO.. */
308 mmuio(KernelBase, 0x00f00000, 0x00080000);
309 /* ROM areas */
310 mmuprotect(KernelBase, 0x00e00000, 0x00080000);
311 mmuprotect(KernelBase, 0x00f80000, 0x00080000);
313 mmuprotectextrom(KernelBase);
315 /* Custom chipset & Clock & Mainboard IO */
316 addr = (ULONG)SysBase->MaxExtMem;
317 if (addr < 0x00d80000)
318 addr = 0x00d80000;
319 mmuio(KernelBase, addr, 0x00e00000 - addr);
320 /* CIA */
321 mmuio(KernelBase, 0x00bfd000, 0x00001000);
322 mmuio(KernelBase, 0x00bfe000, 0x00001000);
323 /* CD32 Akiko */
324 mmuio(KernelBase, 0x00b80000, 0x00001000);
326 //debug_mmu(KernelBase);
328 CacheClearU();
329 enable_mmu(KernelBase);
331 Enable();
333 AROS_USERFUNC_EXIT
335 return NULL;
338 void mmu_end(void) { };