xref: /haiku/headers/private/kernel/arch/m68k/arch_030_mmu.h (revision b06a48ab8f30b45916a9c157b992827779182163)
1 /*
2 ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 ** Distributed under the terms of the OpenBeOS License.
4 */
5 #ifndef _KERNEL_ARCH_M68K_030_MMU_H
6 #define _KERNEL_ARCH_M68K_030_MMU_H
7 
8 
9 #include <SupportDefs.h>
10 #include <string.h>
11 
12 #include <arch_mmu.h>
13 
14 // global pages only available on 040/060
15 //#define MMU_HAS_GLOBAL_PAGES
16 
17 /* This is the normal layout of the descriptors, as per documentation.
18  * When page size > 256, several bits are unused in the LSB of page
19  * addresses, which we can use in addition of other unused bits.
20  * the structs dedlared later reflect this for 4K pages.
21  */
22 											// = names in MC user's manual
23 											// or comments
24 struct short_page_directory_entry {
25 	// upper 32 bits
26 	uint32 addr : 28;						// address
27 	uint32 accessed : 1;					// = used
28 	uint32 write_protect : 1;
29 	uint32 type : 2;						// DT_*
30 };
31 
32 struct long_page_directory_entry {
33 	// upper 32 bits
34 	uint32 low_up : 1;						// limit is lower(1)/upper(0)
35 	uint32 limit : 15;
36 	uint32 _ones : 6;
37 	uint32 _zero2 : 1;
38 	uint32 supervisor : 1;
39 	uint32 _zero1 : 4;
40 	uint32 accessed : 1;					// = used
41 	uint32 write_protect : 1;
42 	uint32 type : 2;
43 	// lower 32 bits
44 	uint32 addr : 28;						// address
45 	uint32 unused : 4;						//
46 };
47 
48 struct short_page_table_entry {
49 	uint32 addr : 24;						// address
50 	uint32 _zero2 : 1;
51 	uint32 cache_disabled : 1;				// = cache_inhibit
52 	uint32 _zero1 : 1;
53 	uint32 dirty : 1;						// = modified
54 	uint32 accessed : 1;					// = used
55 	uint32 write_protect : 1;
56 	uint32 type : 2;
57 };
58 
59 struct long_page_table_entry {
60 	// upper 32 bits
61 	uint32 low_up : 1;						// limit is lower(1)/upper(0)
62 	// limit only used on early table terminators, else unused
63 	uint32 limit : 15;
64 	uint32 _ones : 6;
65 	uint32 _zero3 : 1;
66 	uint32 supervisor : 1;
67 	uint32 _zero2 : 1;
68 	uint32 cache_disabled : 1;				// = cache_inhibit
69 	uint32 _zero1 : 1;
70 	uint32 dirty : 1;						// = modified
71 	uint32 accessed : 1;					// = used
72 	uint32 write_protect : 1;
73 	uint32 type : 2;
74 	// lower 32 bits
75 	uint32 addr : 24;						// address
76 	uint32 unused : 8;						//
77 };
78 
79 /* rarely used */
80 struct short_indirect_entry {
81 	// upper 32 bits
82 	uint32 addr : 30;						// address
83 	uint32 type : 2;						// DT_*
84 };
85 
86 struct long_indirect_entry {
87 	// upper 32 bits
88 	uint32 unused1 : 30;
89 	uint32 type : 2;
90 	// lower 32 bits
91 	uint32 addr : 30;						// address
92 	uint32 unused2 : 2;						//
93 };
94 
95 /* for clarity:
96    - the top level page directory will be called "page root", (root or rtdir)
97    - the 2nd level will be "page directory" like on x86, (pgdir)
98    - the 3rd level is a "page table" as on x86. (pgtbl)
99 */
100 
101 typedef struct short_page_directory_entry page_root_entry;
102 typedef struct short_page_directory_entry page_directory_entry;
103 typedef struct long_page_table_entry page_table_entry;
104 typedef struct long_indirect_entry page_indirect_entry;
105 
106 /* scalar storage type that maps them */
107 typedef uint32 page_root_entry_scalar;
108 typedef uint32 page_directory_entry_scalar;
109 typedef uint64 page_table_entry_scalar;
110 typedef uint64 page_indirect_entry_scalar;
111 
112 #define DT_ROOT DT_VALID_4
113 #define DT_DIR DT_VALID_8
114 //#define DT_PAGE DT_PAGE :)
115 #define DT_INDIRECT DT_VALID_8
116 
117 /* default scalar values for entries */
118 #define DFL_ROOTENT_VAL 0x00000000
119 #define DFL_DIRENT_VAL 0x00000000
120 // limit disabled, 6bits at 1
121 // (limit isn't used on that level, but just in case)
122 #define DFL_PAGEENT_VAL 0x7FFFFC0000000000LL
123 
124 #define NUM_ROOTENT_PER_TBL 128
125 #define NUM_DIRENT_PER_TBL 128
126 #define NUM_PAGEENT_PER_TBL 64
127 
128 /* unlike x86, the root/dir/page table sizes are different than B_PAGE_SIZE
129  * so we will have to fit more than one on a page to avoid wasting space.
130  * We will allocate a group of tables with the one we want inside, and
131  * add them from the aligned index needed, to make it easy to free them.
132  */
133 
134 #define SIZ_ROOTTBL (NUM_ROOTENT_PER_TBL * sizeof(page_root_entry))
135 #define SIZ_DIRTBL (NUM_DIRENT_PER_TBL * sizeof(page_directory_entry))
136 #define SIZ_PAGETBL (NUM_PAGEENT_PER_TBL * sizeof(page_table_entry))
137 
138 //#define NUM_ROOTTBL_PER_PAGE (B_PAGE_SIZE / SIZ_ROOTTBL)
139 #define NUM_DIRTBL_PER_PAGE (B_PAGE_SIZE / SIZ_DIRTBL)
140 #define NUM_PAGETBL_PER_PAGE (B_PAGE_SIZE / SIZ_PAGETBL)
141 
142 /* macros to get the physical page or table number and address of tables from
143  * descriptors */
144 #if 0
145 /* XXX:
146    suboptimal:
147    struct foo {
148    int a:2;
149    int b:30;
150    } v = {...};
151    *(int *)0 = (v.b) << 2;
152    generates:
153    sarl    $2, %eax
154    sall    $2, %eax
155    We use a cast + bitmasking, since all address fields are already shifted
156 */
157 // from a root entry
158 #define PREA_TO_TA(a) ((a) << 4)
159 #define PREA_TO_PN(a) ((a) >> (12-4))
160 #define PREA_TO_PA(a) ((a) << 4)
161 #define TA_TO_PREA(a) ((a) >> 4)
162 //...
163 #endif
164 
165 // TA: table address
166 // PN: page number
167 // PA: page address
168 // PO: page offset (offset of table in page)
169 // PI: page index (index of table relative to page start)
170 
171 // from a root entry
172 #define PRE_TO_TA(a) ((*(uint32 *)(&(a))) & ~((1<<4)-1))
173 #define PRE_TO_PN(e) ((*(uint32 *)(&(e))) >> 12)
174 #define PRE_TO_PA(e) ((*(uint32 *)(&(e))) & ~((1<<12)-1))
175 //#define PRE_TO_PO(e) ((*(uint32 *)(&(e))) & ((1<<12)-1))
176 //#define PRE_TO_PI(e) (((*(uint32 *)(&(e))) & ((1<<12)-1)) / SIZ_DIRTBL)
177 #define TA_TO_PREA(a) ((a) >> 4)
178 // from a directory entry
179 #define PDE_TO_TA(a) ((*(uint32 *)(&(a))) & ~((1<<4)-1))
180 #define PDE_TO_PN(e) ((*(uint32 *)(&(e))) >> 12)
181 #define PDE_TO_PA(e) ((*(uint32 *)(&(e))) & ~((1<<12)-1))
182 //#define PDE_TO_PO(e) ((*(uint32 *)(&(e))) & ((1<<12)-1))
183 //#define PDE_TO_PI(e) (((*(uint32 *)(&(e))) & ((1<<12)-1)) / SIZ_PAGETBL)
184 #define TA_TO_PDEA(a) ((a) >> 4)
185 // from a table entry
186 #define PTE_TO_TA(a) ((((uint32 *)(&(a)))[1]) & ~((1<<8)-1))
187 #define PTE_TO_PN(e) ((((uint32 *)(&(e)))[1]) >> 12)
188 #define PTE_TO_PA(e) ((((uint32 *)(&(e)))[1]) & ~((1<<12)-1))
189 #define TA_TO_PTEA(a) ((a) >> 8)
190 // from an indirect entry
191 #define PIE_TO_TA(a) ((((uint32 *)(&(a)))[1]) & ~((1<<2)-1))
192 #define PIE_TO_PN(e) ((((uint32 *)(&(e)))[1]) >> 12)
193 #define PIE_TO_PA(e) ((((uint32 *)(&(e)))[1]) & ~((1<<12)-1))
194 #define PIE_TO_PO(e) ((((uint32 *)(&(e)))[1]) & ((1<<12)-(1<<2)))
195 #define TA_TO_PIEA(a) ((a) >> 2)
196 
197 /* 7/7/6 split */
198 #define VADDR_TO_PRENT(va) (((va) / B_PAGE_SIZE) / (64*128))
199 #define VADDR_TO_PDENT(va) ((((va) / B_PAGE_SIZE) / 64) % 128)
200 #define VADDR_TO_PTENT(va) (((va) / B_PAGE_SIZE) % 64)
201 
202 #endif	/* _KERNEL_ARCH_M68K_030_MMU_H */
203