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