revert between 56095 -> 55830 in arch
[AROS.git] / arch / m68k-amiga / boot / mmu.c
blob9586b279ea3e340e264cdf715da6eddb8a80acf7
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
7 #include <aros/debug.h>
9 #include <exec/types.h>
10 #include <exec/resident.h>
11 #include <proto/exec.h>
12 #include <proto/kernel.h>
13 #include <proto/expansion.h>
14 #include <proto/utility.h>
15 #include <libraries/configvars.h>
16 #include <hardware/cpu/memory.h>
18 #include "exec_intern.h"
19 #include "early.h"
20 #undef KernelBase
22 #define FASTREMAP 1
24 #define _STR(A) #A
25 #define STR(A) _STR(A)
27 #define NAME "mmu"
28 #define VERSION 41
29 #define REVISION 1
31 static AROS_UFP3 (APTR, Init,
32 AROS_UFPA(struct Library *, lh, D0),
33 AROS_UFPA(BPTR, segList, A0),
34 AROS_UFPA(struct ExecBase *, sysBase, A6));
36 static const TEXT name_string[] = NAME;
37 static const TEXT version_string[] =
38 NAME " " STR(VERSION) "." STR(REVISION) "\n";
40 extern void mmu_end(void);
42 const struct Resident rom_tag =
44 RTC_MATCHWORD,
45 (struct Resident *)&rom_tag,
46 (APTR)&mmu_end,
47 RTF_COLDSTART,
48 VERSION,
49 NT_UNKNOWN,
50 100,
51 (STRPTR)name_string,
52 (STRPTR)version_string,
53 (APTR)Init
56 void enable_mmu(void *kb);
57 void debug_mmu(void *kb);
58 extern BOOL init_mmu(void *kb);
60 extern BYTE _rom_start;
61 extern BYTE _rom_end;
62 extern BYTE _ext_start;
63 extern BYTE _ext_end;
65 static void mmuprotect(void *KernelBase, ULONG addr, ULONG size)
67 KrnSetProtection((void*)addr, size, MAP_Readable | MAP_Executable);
69 static void mmuram(void *KernelBase, ULONG addr, ULONG size)
71 KrnSetProtection((void*)addr, size, MAP_Readable | MAP_Writable | MAP_Executable);
73 static void mmuchipram(void *KernelBase, ULONG addr, ULONG size)
75 KrnSetProtection((void*)addr, size, MAP_Readable | MAP_Writable | MAP_Executable | MAP_CacheInhibit);
77 static void mmuio(void *KernelBase, ULONG addr, ULONG size)
79 KrnSetProtection((void*)addr, size, MAP_Readable | MAP_Writable | MAP_CacheInhibit);
82 static APTR AllocPagesAligned(ULONG pages)
84 APTR ret;
85 ret = AllocMem((pages + 1) * PAGE_SIZE, MEMF_CLEAR | MEMF_FAST | MEMF_REVERSE);
86 if (ret == NULL)
87 return NULL;
88 Forbid();
89 FreeMem(ret, (pages + 1) * PAGE_SIZE);
90 ret = AllocAbs((pages * PAGE_SIZE + PAGE_SIZE - 1) & PAGE_MASK, (APTR)((((ULONG)ret) + PAGE_SIZE - 1) & PAGE_MASK));
91 Permit();
92 return ret;
95 static void swapvbr(APTR vbr)
97 asm volatile (
98 ".chip 68010\n"
99 "move.l %0,%%d0\n"
100 "move.l 4.w,%%a6\n"
101 "move.l %%a5,-(%%sp)\n"
102 "lea newvbr(%%pc),%%a5\n"
103 "jsr -0x1e(%%a6)\n"
104 "move.l (%%sp)+,%%a5\n"
105 "bra.s 0f\n"
106 "newvbr:\n"
107 "movec %%d0,%%vbr\n"
108 "rte\n"
109 "0:\n"
110 : : "m" (vbr) : "d0", "d1", "a5", "a6");
113 static BOOL ISA3000(void)
115 if (!(SysBase->AttnFlags & AFF_68030))
116 return FALSE;
117 if (SysBase->AttnFlags & AFF_68040)
118 return FALSE;
119 if (ReadGayle())
120 return FALSE;
121 /* We should check for RAMSEY.. Later.. */
122 /* 0x07000000 - 0x07ffffff is A3000-only RAM region */
123 return TypeOfMem((APTR)0x07ff0000) != 0;
126 static void mmuprotectregion(void *KernelBase, const UBYTE *name, APTR addr, ULONG size, ULONG flags)
128 ULONG allocsize = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
129 KrnSetProtection(addr, allocsize, 0);
130 if (FASTREMAP && TypeOfMem(addr) & MEMF_CHIP) {
131 APTR newmem = AllocPagesAligned(allocsize / PAGE_SIZE);
132 if (newmem) {
133 CopyMem(addr, newmem, size);
134 D(bug("Remapped %d byte Chip region to Fast, %p - %p -> %p - %p (%s), flags %08x\n",
135 size, addr, addr + size - 1, newmem, newmem + size - 1, name, flags));
136 KrnMapGlobal(addr, newmem, allocsize, flags);
137 return;
140 D(bug("Protected %d byte region %p - %p (%s) using flags %08x\n", size, addr, addr + size - 1, name, flags));
141 KrnSetProtection(addr, allocsize, flags);
144 /* MMU protect ArosBootStrap loaded ROM modules */
145 static void mmuprotectextrom(void *KernelBase)
147 UWORD i;
148 struct MemList *ml;
149 struct BootStruct *bs = GetBootStruct(SysBase);
151 if (bs == NULL)
152 return;
154 ForeachNode(bs->mlist, ml) {
155 if (ml->ml_Node.ln_Type == NT_KICKMEM) {
156 for(i = 0; i < ml->ml_NumEntries; i++) {
157 // me_Length bit 31 is KICKMEM_ALLOCATED bit
158 mmuprotectregion(KernelBase, "ROM", ml->ml_ME[i].me_Addr, ml->ml_ME[i].me_Length & ~0x80000000, MAP_Readable | MAP_Executable);
164 #define MAX_HEADERS 100
166 static AROS_UFH3 (APTR, Init,
167 AROS_UFHA(struct Library *, lh, D0),
168 AROS_UFHA(BPTR, segList, A0),
169 AROS_UFHA(struct ExecBase *, SysBase, A6)
172 AROS_USERFUNC_INIT
174 void *KernelBase;
175 void *ExpansionBase;
176 struct ConfigDev *cd;
177 ULONG addr, size;
178 ULONG *memheaders;
179 struct MemHeader *mh;
180 UWORD i, cnt;
181 char *args;
182 BOOL ZeroPageInvalid = FALSE, ZeroPageProtect = FALSE;
183 BOOL usemmu = FALSE;
184 UBYTE *vbrpage;
185 ULONG *zero = (ULONG*)0;
187 if (!(SysBase->AttnFlags & AFF_68020))
188 return NULL;
190 KernelBase = OpenResource("kernel.resource");
191 if (!KernelBase)
192 return NULL;
194 /* Parse some arguments from command line */
195 args = (char *)LibGetTagData(KRN_CmdLine, 0, KrnGetBootInfo());
196 if (args) {
197 if (strstr(args, "nommu")) {
198 return NULL;
199 } else if (strstr(args, "debugmmu")) {
200 usemmu = TRUE;
201 ZeroPageInvalid = TRUE;
202 } else if (strstr(args, "pmmu")) {
203 usemmu = TRUE;
204 ZeroPageProtect = TRUE;
205 } else if (strstr(args, "mmu")) {
206 usemmu = TRUE;
210 /* if 68030 A3000 = use MMU, we are guaranteed to have full 68030 */
211 if (!usemmu && ISA3000())
212 usemmu = TRUE;
214 /* 68030/68851: Only enable if mmu commandline detected. */
215 if (!(SysBase->AttnFlags & AFF_68040) && !usemmu)
216 return FALSE;
218 if (!init_mmu(KernelBase)) {
219 D(bug("MMU initialization failed\n"));
220 return NULL;
223 D(bug("Initializing MMU setup\n"));
225 vbrpage = AllocPagesAligned(1);
226 if (vbrpage) {
227 /* Move VBR to Fast RAM */
228 CopyMem(zero, vbrpage, PAGE_SIZE);
229 swapvbr(vbrpage);
230 D(bug("VBR %p\n", vbrpage));
231 if (ZeroPageInvalid || ZeroPageProtect) {
232 /* Corrupt original zero page vectors, makes bad programs crash faster if we don't
233 * want MMU special zero page handling */
234 for (i = 0; i < 64; i++) {
235 if (i != 1)
236 zero[i] = 0xdeadf00d;
241 /* RAM */
242 memheaders = AllocVec(sizeof(ULONG) * 2 * MAX_HEADERS, MEMF_PUBLIC);
243 if (!memheaders)
244 return NULL;
245 Forbid();
246 cnt = 0;
247 mh = (struct MemHeader*)SysBase->MemList.lh_Head;
248 while (mh->mh_Node.ln_Succ && cnt < MAX_HEADERS) {
249 memheaders[cnt * 2 + 0] = (ULONG)mh->mh_Lower;
250 memheaders[cnt * 2 + 1] = (ULONG)mh->mh_Upper;
251 cnt++;
252 mh = (struct MemHeader*)(mh->mh_Node.ln_Succ);
254 Permit();
255 for (i = 0; i < cnt; i++) {
256 ULONG tm;
257 addr = memheaders[i * 2 + 0];
258 addr &= PAGE_MASK;
259 size = memheaders[i * 2 + 1] - addr;
260 size += PAGE_SIZE - 1;
261 size &= PAGE_MASK;
262 tm = TypeOfMem((void*)(addr + 2 * PAGE_SIZE));
263 if (tm & MEMF_CHIP)
264 mmuchipram(KernelBase, addr, size);
265 else if (tm & MEMF_FAST)
266 mmuram(KernelBase, addr, size);
268 FreeVec(memheaders);
269 if (ReadGayle()) {
270 /* PCMCIA regions */
271 mmuram(KernelBase, 0x00600000, 0x00400000);
272 mmuio(KernelBase, 0x00a00000, 0x00050000);
275 if (ZeroPageInvalid) {
276 /* Mark "zero page" invalid, MMU support handles ExecBase fetches transparently.
277 * Special bus error handler checks if access was LONG READ from address 4.
279 KrnSetProtection(0, PAGE_SIZE, 0);
280 } else if (ZeroPageProtect) {
281 /* Remap zero page to Fast RAM, faster SysBase access */
282 mmuprotectregion(KernelBase, "ZeroPage", 0, PAGE_SIZE, MAP_Readable);
283 } else {
284 /* No special protection, cacheable */
285 KrnSetProtection(0, PAGE_SIZE, MAP_Readable | MAP_Writable);
287 /* Protect Supervisor stack if MMU debugging mode */
288 mmuprotectregion(KernelBase, "SS_Stack", SysBase->SysStkLower, SysBase->SysStkUpper - SysBase->SysStkLower,
289 MAP_Readable | MAP_Writable | ((ZeroPageInvalid || ZeroPageProtect) ? MAP_Supervisor : 0));
291 /* Expansion IO devices */
292 ExpansionBase = TaggedOpenLibrary(TAGGEDOPEN_EXPANSION);
293 cd = NULL;
294 while ((cd = FindConfigDev(cd, -1, -1))) {
295 if (cd->cd_Rom.er_Type & ERTF_MEMLIST)
296 continue;
297 /* Mark all non-RAM (IO) regions as noncacheabled */
298 mmuio(KernelBase, (ULONG)cd->cd_BoardAddr, cd->cd_BoardSize);
300 CloseLibrary(ExpansionBase);
302 /* Some boards may use this as an IO.. */
303 mmuio(KernelBase, 0x00f00000, 0x00080000);
304 /* ROM areas */
305 mmuprotect(KernelBase, 0x00e00000, 0x00080000);
306 mmuprotect(KernelBase, 0x00f80000, 0x00080000);
308 mmuprotectextrom(KernelBase);
310 /* Custom chipset & Clock & Mainboard IO */
311 addr = (ULONG)SysBase->MaxExtMem;
312 if (addr < 0x00d80000)
313 addr = 0x00d80000;
314 mmuio(KernelBase, addr, 0x00e00000 - addr);
315 /* CIA */
316 mmuio(KernelBase, 0x00bfd000, 0x00001000);
317 mmuio(KernelBase, 0x00bfe000, 0x00001000);
318 /* CD32 Akiko */
319 mmuio(KernelBase, 0x00b80000, 0x00001000);
321 //debug_mmu(KernelBase);
323 CacheClearU();
324 enable_mmu(KernelBase);
326 AROS_USERFUNC_EXIT
328 return NULL;
331 void mmu_end(void) { };