1/*
2 * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
3 * Based on code written by Travis Geiselbrecht for NewOS.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8
9#include "mmu.h"
10
11#include <boot/platform.h>
12#include <boot/stdio.h>
13#include <boot/kernel_args.h>
14#include <boot/stage2.h>
15#include <arch/cpu.h>
16#include <arch_kernel.h>
17#include <kernel.h>
18
19#include <OS.h>
20
21#include <string.h>
22
23#include "arch_030_mmu.h"
24
25
26#define TRACE_MMU
27#ifdef TRACE_MMU
28#	define TRACE(x) dprintf x
29#else
30#	define TRACE(x) ;
31#endif
32
33
34extern page_root_entry *gPageRoot;
35
36
37static void
38initialize(void)
39{
40	TRACE(("mmu_030:initialize\n"));
41}
42
43
44static status_t
45set_tt(int which, addr_t pa, size_t len, uint32 perms)
46{
47	TRACE(("mmu_030:set_tt(%d, 0x%lx, 0x%lx, 0x%08lx)\n", which, pa, len, perms));
48	uint32 mask;
49	uint32 ttr = 0;
50	mask = 0x0000ffff;
51	if (len) {
52		len = (len >> 24) & 0x00ff;
53		while (len >>= 1)
54			mask <<= 1;
55		// enable, cachable(?), r/w
56		// super only
57		// mc68030 user's manual, page 9-57
58		ttr = 0x08043;
59		ttr |= (pa & 0xff000000);
60		ttr |= (mask & 0x00ff0000);
61	}
62	TRACE(("mmu_030:set_tt: 0x%08lx\n", ttr));
63
64	/* as seen in linux and BSD code,
65	 * we need to use .chip pseudo op here as -m68030 doesn't seem to help gas grok it.
66	 */
67	switch (which) {
68		case 0:
69			asm volatile(  \
70				".chip 68030\n\t"				\
71				"pmove %%tt0,(%0)\n\t"				\
72				".chip 68k\n\t"					\
73				: : "a"(&ttr));
74			break;
75		case 1:
76			asm volatile(  \
77				".chip 68030\n\t"				\
78				"pmove (%0),%%tt1\n"				\
79				".chip 68k\n\t"					\
80				: : "a"(&ttr));
81			break;
82		default:
83			return EINVAL;
84	}
85	return B_OK;
86}
87
88
89static status_t
90load_rp(addr_t pa)
91{
92	TRACE(("mmu_030:load_rp(0x%lx)\n", pa));
93	long_page_directory_entry entry;
94	*(uint64 *)&entry = DFL_PAGEENT_VAL;
95	entry.type = DT_ROOT;
96	entry.addr = TA_TO_PREA(((addr_t)pa));
97
98	asm volatile( \
99		"pmove (%0),%%srp\n" \
100		"pmove (%0),%%crp\n" \
101		: : "a"((uint64 *)&entry));
102	return B_OK;
103}
104
105
106static status_t
107allocate_kernel_pgdirs(void)
108{
109	page_root_entry *pr = gPageRoot;
110	page_directory_entry *pd;
111	addr_t tbl;
112	int i;
113
114	// we'll fill in the 2nd half with ready made page dirs
115	for (i = NUM_ROOTENT_PER_TBL/2; i < NUM_ROOTENT_PER_TBL; i++) {
116		if (i % NUM_DIRTBL_PER_PAGE)
117			tbl += SIZ_DIRTBL;
118		else
119			tbl = mmu_get_next_page_tables();
120		pr[i].addr = TA_TO_PREA(tbl);
121		pr[i].type = DT_ROOT;
122		pd = (page_directory_entry *)tbl;
123		for (int32 j = 0; j < NUM_DIRENT_PER_TBL; j++)
124			*(page_directory_entry_scalar *)(&pd[j]) = DFL_DIRENT_VAL;
125	}
126	return B_OK;
127}
128
129
130static status_t
131enable_paging(void)
132{
133	TRACE(("mmu_030:enable_paging\n"));
134	return B_NO_INIT;
135}
136
137
138const struct boot_mmu_ops k030MMUOps = {
139	&initialize,
140	&set_tt,
141	&load_rp,
142	&allocate_kernel_pgdirs,
143	&enable_paging
144};
145