xref: /haiku/src/system/kernel/arch/m68k/arch_vm_translation_map_impl.cpp (revision 020cbad9d40235a2c50a81a42d69912a5ff8fbc4)
1 /*
2  * Copyright 2007, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  * 		François Revol <revol@free.fr>
7  *
8  * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de.
9  * Distributed under the terms of the MIT License.
10  *
11  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
12  * Distributed under the terms of the NewOS License.
13  */
14 
15 #ifndef ARCH_M68K_MMU_TYPE
16 #error This file is included from arch_*_mmu.cpp
17 #endif
18 
19 /*  (mmu_man) Implementation details on 68030 and others:
20 
21 	Unlike on x86 we can't just switch the context to another team by just
22 	setting a register to another page directory, since we only have one
23 	page table containing both kernel and user address mappings.
24 	The 030 supports arbitrary layout of the page directory tree, including
25 	a 1-bit first level (2 entries top level table) that would map kernel
26 	and user land at a single place. But 040 and later only support a fixed
27 	splitting of 7/7/6 for 4K pages.
28 
29 	Since 68k SMP hardware is rare enough we don't want to support them, we
30 	can take some shortcuts.
31 
32 	As we don't want a separate user and kernel space, we'll use a single
33 	table. With the 7/7/6 split the 2nd level would require 32KB of tables,
34 	which is small enough to not want to use the list hack from x86.
35 	XXX: we use the hack for now, check later
36 
37 	Since page directories/tables don't fit exactly a page, we stuff more
38 	than one per page, and allocate them all at once, and add them at the
39 	same time to the tree. So we guarantee all higher-level entries modulo
40 	the number of tables/page are either invalid or present.
41  */
42 
43 #include <KernelExport.h>
44 #include <kernel.h>
45 #include <vm.h>
46 #include <vm_address_space.h>
47 #include <vm_priv.h>
48 #include <int.h>
49 #include <boot/kernel_args.h>
50 #include <arch/vm_translation_map.h>
51 #include <arch/cpu.h>
52 #include <arch_mmu.h>
53 #include <stdlib.h>
54 
55 #include "generic_vm_physical_page_mapper.h"
56 
57 
58 
59 //#define TRACE_VM_TMAP
60 #ifdef TRACE_VM_TMAP
61 #	define TRACE(x) dprintf x
62 #else
63 #	define TRACE(x) ;
64 #endif
65 
66 //XXX: that's platform specific!
67 // 14 MB of iospace
68 #define IOSPACE_SIZE (14*1024*1024)
69 // 4 MB chunks, to optimize for 4 MB pages
70 // XXX: no such thing on 68k (060 ?)
71 // 256K
72 #define IOSPACE_CHUNK_SIZE (256*1024)
73 
74 static page_table_entry *iospace_pgtables = NULL;
75 
76 #define PAGE_INVALIDATE_CACHE_SIZE 64
77 
78 // vm_translation object stuff
79 typedef struct vm_translation_map_arch_info {
80 	page_root_entry *rtdir_virt;
81 	page_root_entry *rtdir_phys;
82 	int num_invalidate_pages;
83 	addr_t pages_to_invalidate[PAGE_INVALIDATE_CACHE_SIZE];
84 } vm_translation_map_arch_info;
85 
86 #if 1//XXX ?
87 static page_table_entry *page_hole = NULL;
88 static page_directory_entry *page_hole_pgdir = NULL;
89 #endif
90 static page_root_entry *sKernelPhysicalPageRoot = NULL;
91 static page_root_entry *sKernelVirtualPageRoot = NULL;
92 static addr_t sQueryPage = NULL;
93 //static page_table_entry *sQueryPageTable;
94 //static page_directory_entry *sQueryPageDir;
95 // MUST be aligned
96 static page_table_entry sQueryDesc __attribute__ (( aligned (4) ));
97 
98 static vm_translation_map *tmap_list;
99 static spinlock tmap_list_lock;
100 
101 static addr_t sIOSpaceBase;
102 
103 #define CHATTY_TMAP 0
104 
105 #if 0
106 // use P*E_TO_* and TA_TO_P*EA !
107 #define ADDR_SHIFT(x) ((x)>>12)
108 #define ADDR_REVERSE_SHIFT(x) ((x)<<12)
109 #endif
110 
111 /* 7/7/6 split */
112 #define VADDR_TO_PRENT(va) (((va) / B_PAGE_SIZE) / (64*128))
113 #define VADDR_TO_PDENT(va) ((((va) / B_PAGE_SIZE) / 64) % 128)
114 #define VADDR_TO_PTENT(va) (((va) / B_PAGE_SIZE) % 64)
115 
116 #define FIRST_USER_PGROOT_ENT    (VADDR_TO_PRENT(USER_BASE))
117 #define FIRST_USER_PGDIR_ENT    (VADDR_TO_PDENT(USER_BASE))
118 #define NUM_USER_PGROOT_ENTS     (VADDR_TO_PRENT(ROUNDUP(USER_SIZE, B_PAGE_SIZE * 64 * 128)))
119 #define NUM_USER_PGDIR_ENTS     (VADDR_TO_PDENT(ROUNDUP(USER_SIZE, B_PAGE_SIZE * 64)))
120 #define FIRST_KERNEL_PGROOT_ENT  (VADDR_TO_PRENT(KERNEL_BASE))
121 #define FIRST_KERNEL_PGDIR_ENT  (VADDR_TO_PDENT(KERNEL_BASE))
122 #define NUM_KERNEL_PGROOT_ENTS   (VADDR_TO_PRENT(KERNEL_SIZE))
123 #define NUM_KERNEL_PGDIR_ENTS   (VADDR_TO_PDENT(KERNEL_SIZE))
124 #define IS_KERNEL_MAP(map)		(map->arch_data->rtdir_phys == sKernelPhysicalPageRoot)
125 
126 static status_t early_query(addr_t va, addr_t *out_physical);
127 static status_t get_physical_page_tmap(addr_t pa, addr_t *va, uint32 flags);
128 static status_t put_physical_page_tmap(addr_t va);
129 
130 static void flush_tmap(vm_translation_map *map);
131 
132 
133 static void *
134 m68k_translation_map_get_pgdir(vm_translation_map *map)
135 {
136 	return map->arch_data->rtdir_phys;
137 }
138 
139 
140 static inline void
141 init_page_root_entry(page_root_entry *entry)
142 {
143 	// DT_INVALID is 0
144 	*(page_root_entry_scalar *)entry = DFL_ROOTENT_VAL;
145 }
146 
147 
148 static inline void
149 update_page_root_entry(page_root_entry *entry, page_root_entry *with)
150 {
151 	// update page directory entry atomically
152 	*(page_root_entry_scalar *)entry = *(page_root_entry_scalar *)with;
153 }
154 
155 
156 static inline void
157 init_page_directory_entry(page_directory_entry *entry)
158 {
159 	*(page_directory_entry_scalar *)entry = DFL_DIRENT_VAL;
160 }
161 
162 
163 static inline void
164 update_page_directory_entry(page_directory_entry *entry, page_directory_entry *with)
165 {
166 	// update page directory entry atomically
167 	*(page_directory_entry_scalar *)entry = *(page_directory_entry_scalar *)with;
168 }
169 
170 
171 static inline void
172 init_page_table_entry(page_table_entry *entry)
173 {
174 	*(page_table_entry_scalar *)entry = DFL_PAGEENT_VAL;
175 }
176 
177 
178 static inline void
179 update_page_table_entry(page_table_entry *entry, page_table_entry *with)
180 {
181 	// update page table entry atomically
182 	// XXX: is it ?? (long desc?)
183 	*(page_table_entry_scalar *)entry = *(page_table_entry_scalar *)with;
184 }
185 
186 
187 static void
188 _update_all_pgdirs(int index, page_root_entry e)
189 {
190 	vm_translation_map *entry;
191 	unsigned int state = disable_interrupts();
192 
193 	acquire_spinlock(&tmap_list_lock);
194 
195 	for(entry = tmap_list; entry != NULL; entry = entry->next)
196 		entry->arch_data->rtdir_virt[index] = e;
197 
198 	release_spinlock(&tmap_list_lock);
199 	restore_interrupts(state);
200 }
201 
202 
203 // XXX currently assumes this translation map is active
204 
205 static status_t
206 early_query(addr_t va, addr_t *_physicalAddress)
207 {
208 	page_table_entry *pentry;
209 
210 	if (page_hole_pgdir[VADDR_TO_PDENT(va)].type != DT_DIR) {
211 		// no pagetable here
212 		return B_ERROR;
213 	}
214 #warning M68K: va or VADDR_TO_PTENT(va) ??
215 	pentry = page_hole + va / B_PAGE_SIZE;
216 	if (pentry->type != DT_PAGE) {
217 		// page mapping not valid
218 		return B_ERROR;
219 	}
220 
221 	*_physicalAddress = PTE_TO_PA(*pentry);
222 	return B_OK;
223 }
224 
225 
226 /*!	Acquires the map's recursive lock, and resets the invalidate pages counter
227 	in case it's the first locking recursion.
228 */
229 static status_t
230 lock_tmap(vm_translation_map *map)
231 {
232 	TRACE(("lock_tmap: map %p\n", map));
233 
234 	recursive_lock_lock(&map->lock);
235 	if (recursive_lock_get_recursion(&map->lock) == 1) {
236 		// we were the first one to grab the lock
237 		TRACE(("clearing invalidated page count\n"));
238 		map->arch_data->num_invalidate_pages = 0;
239 	}
240 
241 	return B_OK;
242 }
243 
244 
245 /*!	Unlocks the map, and, if we'll actually losing the recursive lock,
246 	flush all pending changes of this map (ie. flush TLB caches as
247 	needed).
248 */
249 static status_t
250 unlock_tmap(vm_translation_map *map)
251 {
252 	TRACE(("unlock_tmap: map %p\n", map));
253 
254 	if (recursive_lock_get_recursion(&map->lock) == 1) {
255 		// we're about to release it for the last time
256 		flush_tmap(map);
257 	}
258 
259 	recursive_lock_unlock(&map->lock);
260 	return B_OK;
261 }
262 
263 
264 static void
265 destroy_tmap(vm_translation_map *map)
266 {
267 	int state;
268 	vm_translation_map *entry;
269 	vm_translation_map *last = NULL;
270 	unsigned int i, j;
271 
272 	if (map == NULL)
273 		return;
274 
275 	// remove it from the tmap list
276 	state = disable_interrupts();
277 	acquire_spinlock(&tmap_list_lock);
278 
279 	entry = tmap_list;
280 	while (entry != NULL) {
281 		if (entry == map) {
282 			if (last != NULL)
283 				last->next = entry->next;
284 			else
285 				tmap_list = entry->next;
286 
287 			break;
288 		}
289 		last = entry;
290 		entry = entry->next;
291 	}
292 
293 	release_spinlock(&tmap_list_lock);
294 	restore_interrupts(state);
295 
296 	if (map->arch_data->rtdir_virt != NULL) {
297 		// cycle through and free all of the user space pgtables
298 		// since the size of tables don't match B_PAEG_SIZE,
299 		// we alloc several at once, based on modulos,
300 		// we make sure they are either all in the tree or none.
301 		for (i = VADDR_TO_PRENT(USER_BASE); i <= VADDR_TO_PRENT(USER_BASE + (USER_SIZE - 1)); i++) {
302 			addr_t pgdir_pn;
303 			page_directory_entry *pgdir;
304 			vm_page *dirpage;
305 
306 			if (map->arch_data->rtdir_virt[i].type == DT_INVALID)
307 				continue;
308 			if (map->arch_data->rtdir_virt[i].type != DT_ROOT) {
309 				panic("rtdir[%d]: buggy descriptor type", i);
310 				return;
311 			}
312 			// suboptimal (done 8 times)
313 			pgdir_pn = PRE_TO_PA(map->arch_data->rtdir_virt[i]);
314 			dirpage = vm_lookup_page(pgdir_pn);
315 			pgdir = &(((page_directory_entry *)dirpage)[i%NUM_DIRTBL_PER_PAGE]);
316 
317 			for (j = 0; j <= NUM_DIRENT_PER_TBL; j+=NUM_PAGETBL_PER_PAGE) {
318 				addr_t pgtbl_pn;
319 				page_table_entry *pgtbl;
320 				vm_page *page;
321 				if (pgdir[j].type == DT_INVALID)
322 					continue;
323 				if (pgdir[j].type != DT_DIR) {
324 					panic("rtdir[%d][%d]: buggy descriptor type", i, j);
325 					return;
326 				}
327 				pgtbl_pn = PDE_TO_PN(pgdir[j]);
328 				page = vm_lookup_page(pgtbl_pn);
329 				pgtbl = (page_table_entry *)page;
330 
331 				if (!page) {
332 					panic("destroy_tmap: didn't find pgtable page\n");
333 					return;
334 				}
335 				vm_page_set_state(page, PAGE_STATE_FREE);
336 			}
337 			if (((i+1)%NUM_DIRTBL_PER_PAGE) == 0)
338 				vm_page_set_state(dirpage, PAGE_STATE_FREE);
339 		}
340 		free(map->arch_data->rtdir_virt);
341 	}
342 
343 	free(map->arch_data);
344 	recursive_lock_destroy(&map->lock);
345 }
346 
347 
348 static void
349 put_pgdir_in_pgroot(page_root_entry *entry,
350 	addr_t pgdir_phys, uint32 attributes)
351 {
352 	page_root_entry dir;
353 	// put it in the pgdir
354 	init_page_root_entry(&dir);
355 	dir.addr = TA_TO_PREA(pgdir_phys);
356 
357 	// ToDo: we ignore the attributes of the page table - for compatibility
358 	//	with BeOS we allow having user accessible areas in the kernel address
359 	//	space. This is currently being used by some drivers, mainly for the
360 	//	frame buffer. Our current real time data implementation makes use of
361 	//	this fact, too.
362 	//	We might want to get rid of this possibility one day, especially if
363 	//	we intend to port it to a platform that does not support this.
364 	//dir.user = 1;
365 	//dir.rw = 1;
366 	dir.type = DT_ROOT;
367 	update_page_root_entry(entry, &dir);
368 }
369 
370 
371 static void
372 put_pgtable_in_pgdir(page_directory_entry *entry,
373 	addr_t pgtable_phys, uint32 attributes)
374 {
375 	page_directory_entry table;
376 	// put it in the pgdir
377 	init_page_directory_entry(&table);
378 	table.addr = TA_TO_PDEA(pgtable_phys);
379 
380 	// ToDo: we ignore the attributes of the page table - for compatibility
381 	//	with BeOS we allow having user accessible areas in the kernel address
382 	//	space. This is currently being used by some drivers, mainly for the
383 	//	frame buffer. Our current real time data implementation makes use of
384 	//	this fact, too.
385 	//	We might want to get rid of this possibility one day, especially if
386 	//	we intend to port it to a platform that does not support this.
387 	//table.user = 1;
388 	//table.rw = 1;
389 	table.type = DT_DIR;
390 	update_page_directory_entry(entry, &table);
391 }
392 
393 
394 static void
395 put_page_table_entry_in_pgtable(page_table_entry *entry,
396 	addr_t physicalAddress, uint32 attributes, bool globalPage)
397 {
398 	page_table_entry page;
399 	init_page_table_entry(&page);
400 
401 	page.addr = TA_TO_PTEA(physicalAddress);
402 
403 	// if the page is user accessible, it's automatically
404 	// accessible in kernel space, too (but with the same
405 	// protection)
406 	page.supervisor = (attributes & B_USER_PROTECTION) == 0;
407 	if (page.supervisor)
408 		page.write_protect = (attributes & B_KERNEL_WRITE_AREA) == 0;
409 	else
410 		page.write_protect = (attributes & B_WRITE_AREA) == 0;
411 	page.type = DT_PAGE;
412 
413 #ifdef PAGE_HAS_GLOBAL_BIT
414 	if (globalPage)
415 		page.global = 1;
416 #endif
417 
418 	// put it in the page table
419 	update_page_table_entry(entry, &page);
420 }
421 
422 
423 static void
424 put_page_indirect_entry_in_pgtable(page_indirect_entry *entry,
425 	addr_t physicalAddress, uint32 attributes, bool globalPage)
426 {
427 	page_indirect_entry page;
428 	init_page_table_entry(&page);
429 
430 	page.addr = TA_TO_PIEA(physicalAddress);
431 	page.type = DT_INDIRECT;
432 
433 	// there are no protection bits in indirect descriptor usually.
434 
435 	// put it in the page table
436 	update_page_table_entry(entry, &page);
437 }
438 
439 
440 static size_t
441 map_max_pages_need(vm_translation_map */*map*/, addr_t start, addr_t end)
442 {
443 	size_t need;
444 	size_t pgdirs = VADDR_TO_PRENT(end) + 1 - VADDR_TO_PRENT(start);
445 	// how much for page directories
446 	need = (pgdirs + NUM_DIRTBL_PER_PAGE - 1) / NUM_DIRTBL_PER_PAGE;
447 	// and page tables themselves
448 	need = ((pgdirs * NUM_DIRENT_PER_TBL) + NUM_PAGETBL_PER_PAGE - 1) / NUM_PAGETBL_PER_PAGE;
449 
450 	// better rounding when only 1 pgdir
451 	// XXX: do better for other cases
452 	if (pgdirs == 1) {
453 		need = 1;
454 		need += (VADDR_TO_PDENT(end) + 1 - VADDR_TO_PDENT(start) + NUM_PAGETBL_PER_PAGE - 1) / NUM_PAGETBL_PER_PAGE;
455 	}
456 
457 	return need;
458 }
459 
460 
461 static status_t
462 map_tmap(vm_translation_map *map, addr_t va, addr_t pa, uint32 attributes)
463 {
464 	page_root_entry *pr;
465 	page_directory_entry *pd;
466 	page_table_entry *pt;
467 	addr_t pd_pg, pt_pg;
468 	unsigned int rindex, dindex, pindex;
469 	int err;
470 
471 	TRACE(("map_tmap: entry pa 0x%lx va 0x%lx\n", pa, va));
472 
473 /*
474 	dprintf("pgdir at 0x%x\n", pgdir);
475 	dprintf("index is %d\n", va / B_PAGE_SIZE / 1024);
476 	dprintf("final at 0x%x\n", &pgdir[va / B_PAGE_SIZE / 1024]);
477 	dprintf("value is 0x%x\n", *(int *)&pgdir[va / B_PAGE_SIZE / 1024]);
478 	dprintf("present bit is %d\n", pgdir[va / B_PAGE_SIZE / 1024].present);
479 	dprintf("addr is %d\n", pgdir[va / B_PAGE_SIZE / 1024].addr);
480 */
481 	pr = map->arch_data->rtdir_virt;
482 
483 	// check to see if a page directory exists for this range
484 	rindex = VADDR_TO_PRENT(va);
485 	if (pr[rindex].type != DT_ROOT) {
486 		addr_t pgdir;
487 		vm_page *page;
488 		unsigned int i;
489 
490 		// we need to allocate a pgtable
491 		page = vm_page_allocate_page(PAGE_STATE_CLEAR, true);
492 
493 		// mark the page WIRED
494 		vm_page_set_state(page, PAGE_STATE_WIRED);
495 
496 		pgdir = page->physical_page_number * B_PAGE_SIZE;
497 
498 		TRACE(("map_tmap: asked for free page for pgdir. 0x%lx\n", pgdir));
499 
500 		// for each pgdir on the allocated page:
501 		for (i = 0; i < NUM_DIRTBL_PER_PAGE; i++) {
502 			unsigned aindex = rindex & ~(NUM_DIRTBL_PER_PAGE-1); /* aligned */
503 			page_root_entry *apr = &pr[aindex + i];
504 
505 			// put in the pgdir
506 			put_pgdir_in_pgroot(apr, pgdir, attributes
507 				| (attributes & B_USER_PROTECTION ? B_WRITE_AREA : B_KERNEL_WRITE_AREA));
508 
509 			// update any other page directories, if it maps kernel space
510 			//XXX: suboptimal, should batch them
511 			if ((aindex+i) >= FIRST_KERNEL_PGDIR_ENT
512 				&& (aindex+i) < (FIRST_KERNEL_PGDIR_ENT + NUM_KERNEL_PGDIR_ENTS))
513 				_update_all_pgdirs((aindex+i), pr[aindex+i]);
514 
515 			pgdir += SIZ_DIRTBL;
516 		}
517 #warning M68K: really mean map_count++ ??
518 		map->map_count++;
519 	}
520 	// now, fill in the pentry
521 	do {
522 		err = get_physical_page_tmap(PRE_TO_PA(pr[rindex]),
523 				&pd_pg, PHYSICAL_PAGE_NO_WAIT);
524 	} while (err < 0);
525 	pd = (page_directory_entry *)pd_pg;
526 	// we want the table at rindex, not at rindex%(tbl/page)
527 	pd += (rindex % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL;
528 
529 	// check to see if a page table exists for this range
530 	dindex = VADDR_TO_PDENT(va);
531 	if (pd[dindex].type != DT_DIR) {
532 		addr_t pgtable;
533 		vm_page *page;
534 		unsigned int i;
535 
536 		// we need to allocate a pgtable
537 		page = vm_page_allocate_page(PAGE_STATE_CLEAR, true);
538 
539 		// mark the page WIRED
540 		vm_page_set_state(page, PAGE_STATE_WIRED);
541 
542 		pgtable = page->physical_page_number * B_PAGE_SIZE;
543 
544 		TRACE(("map_tmap: asked for free page for pgtable. 0x%lx\n", pgtable));
545 
546 		// for each pgtable on the allocated page:
547 		for (i = 0; i < NUM_PAGETBL_PER_PAGE; i++) {
548 			unsigned aindex = dindex & ~(NUM_PAGETBL_PER_PAGE-1); /* aligned */
549 			page_directory_entry *apd = &pd[aindex + i];
550 
551 			// put in the pgdir
552 			put_pgtable_in_pgdir(apd, pgtable, attributes
553 				| (attributes & B_USER_PROTECTION ? B_WRITE_AREA : B_KERNEL_WRITE_AREA));
554 
555 			// no need to update other page directories for kernel space;
556 			// the root-level already point to us.
557 
558 			pgtable += SIZ_PAGETBL;
559 		}
560 
561 #warning M68K: really mean map_count++ ??
562 		map->map_count++;
563 	}
564 	// now, fill in the pentry
565 	do {
566 		err = get_physical_page_tmap(PDE_TO_PA(pd[dindex]),
567 				&pt_pg, PHYSICAL_PAGE_NO_WAIT);
568 	} while (err < 0);
569 	pt = (page_table_entry *)pt_pg;
570 	// we want the table at rindex, not at rindex%(tbl/page)
571 	pt += (dindex % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL;
572 
573 	pindex = VADDR_TO_PTENT(va);
574 
575 	put_page_table_entry_in_pgtable(&pt[pindex], pa, attributes,
576 		IS_KERNEL_MAP(map));
577 
578 	put_physical_page_tmap(pt_pg);
579 	put_physical_page_tmap(pd_pg);
580 
581 	if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE)
582 		map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = va;
583 
584 	map->arch_data->num_invalidate_pages++;
585 
586 	map->map_count++;
587 
588 	return 0;
589 }
590 
591 
592 static status_t
593 unmap_tmap(vm_translation_map *map, addr_t start, addr_t end)
594 {
595 	page_table_entry *pt;
596 	page_directory_entry *pd;
597 	page_root_entry *pr = map->arch_data->rtdir_virt;
598 	addr_t pd_pg, pt_pg;
599 	status_t status;
600 	int index;
601 
602 	start = ROUNDOWN(start, B_PAGE_SIZE);
603 	end = ROUNDUP(end, B_PAGE_SIZE);
604 
605 	TRACE(("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end));
606 
607 restart:
608 	if (start >= end)
609 		return B_OK;
610 
611 	index = VADDR_TO_PRENT(start);
612 	if (pr[index].type != DT_ROOT) {
613 		// no pagedir here, move the start up to access the next page table
614 		start = ROUNDUP(start + 1, B_PAGE_SIZE);
615 		goto restart;
616 	}
617 
618 	do {
619 		status = get_physical_page_tmap(PRE_TO_PA(pr[index]),
620 			&pd_pg, PHYSICAL_PAGE_NO_WAIT);
621 	} while (status < B_OK);
622 	pd = (page_directory_entry *)pd_pg;
623 	// we want the table at rindex, not at rindex%(tbl/page)
624 	pd += (index % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL;
625 
626 	index = VADDR_TO_PDENT(start);
627 	if (pd[index].type != DT_DIR) {
628 		// no pagetable here, move the start up to access the next page table
629 		start = ROUNDUP(start + 1, B_PAGE_SIZE);
630 		put_physical_page_tmap(pd_pg);
631 		goto restart;
632 	}
633 
634 	do {
635 		status = get_physical_page_tmap(PDE_TO_PA(pd[index]),
636 			&pt_pg, PHYSICAL_PAGE_NO_WAIT);
637 	} while (status < B_OK);
638 	pt = (page_table_entry *)pt_pg;
639 	// we want the table at rindex, not at rindex%(tbl/page)
640 	pt += (index % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL;
641 
642 	for (index = VADDR_TO_PTENT(start);
643 			(index < NUM_PAGEENT_PER_TBL) && (start < end);
644 			index++, start += B_PAGE_SIZE) {
645 		if (pt[index].type != DT_PAGE && pt[index].type != DT_INDIRECT) {
646 			// page mapping not valid
647 			continue;
648 		}
649 
650 		TRACE(("unmap_tmap: removing page 0x%lx\n", start));
651 
652 		pt[index].type = DT_INVALID;
653 		map->map_count--;
654 
655 		if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE)
656 			map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = start;
657 
658 		map->arch_data->num_invalidate_pages++;
659 	}
660 
661 	put_physical_page_tmap(pt_pg);
662 	put_physical_page_tmap(pd_pg);
663 
664 	goto restart;
665 }
666 
667 // XXX: 040 should be able to do that with PTEST (but not 030 or 060)
668 static status_t
669 query_tmap_interrupt(vm_translation_map *map, addr_t va, addr_t *_physical,
670 	uint32 *_flags)
671 {
672 	page_root_entry *pr = map->arch_data->rtdir_virt;
673 	page_directory_entry *pd;
674 	page_indirect_entry *pi;
675 	page_table_entry *pt;
676 	addr_t physicalPageTable;
677 	int32 cpu = smp_get_current_cpu();
678 	int32 index;
679 	status_t err = B_ERROR;	// no pagetable here
680 
681 	if (sQueryPage == NULL)
682 		return err; // not yet initialized !?
683 
684 	index = VADDR_TO_PRENT(va);
685 	if (pr && pr[index].type == DT_ROOT) {
686 		put_page_table_entry_in_pgtable(&sQueryDesc, PRE_TO_TA(pr[index]), B_KERNEL_READ_AREA, false);
687 		invalidate_TLB(pt);
688 		pd = (page_directory_entry *)sQueryPage;
689 		index = VADDR_TO_PDENT(va);
690 
691 		if (pd && pd[index].type == DT_DIR) {
692 			put_page_table_entry_in_pgtable(&sQueryDesc, PDE_TO_TA(pd[index]), B_KERNEL_READ_AREA, false);
693 			invalidate_TLB(pt);
694 			pt = (page_table_entry *)sQueryPage;
695 			index = VADDR_TO_PTENT(va);
696 
697 			if (pt && pt[index].type == DT_INDIRECT) {
698 				pi = pt;
699 				put_page_table_entry_in_pgtable(&sQueryDesc, PIE_TO_TA(pi[index]), B_KERNEL_READ_AREA, false);
700 				invalidate_TLB(pt);
701 				pt = (page_table_entry *)sQueryPage;
702 				index = 0; // single descriptor
703 			}
704 
705 			if (pt /*&& pt[index].type == DT_PAGE*/) {
706 				*_physical = PTE_TO_PA(pt[index]);
707 				// we should only be passed page va, but just in case.
708 				*_physical += va % B_PAGE_SIZE;
709 				*_flags |= ((pt[index].write_protect ? 0 : B_KERNEL_WRITE_AREA : 0) | B_KERNEL_READ_AREA)
710 						| (pt[index].dirty ? PAGE_MODIFIED : 0)
711 						| (pt[index].accessed ? PAGE_ACCESSED : 0)
712 						| ((pt[index].type == DT_PAGE) ? PAGE_PRESENT : 0);
713 				err = B_OK;
714 			}
715 	}
716 
717 	// unmap the pg table from the indirect desc.
718 	sQueryDesc.type = DT_INVALID;
719 
720 	return err;
721 }
722 
723 
724 static status_t
725 query_tmap(vm_translation_map *map, addr_t va, addr_t *_physical, uint32 *_flags)
726 {
727 	page_table_entry *pt;
728 	page_indirect_entry *pi;
729 	page_directory_entry *pd;
730 	page_directory_entry *pr = map->arch_data->rtdir_virt;
731 	addr_t pd_pg, pt_pg, pi_pg;
732 	status_t status;
733 	int32 index;
734 
735 	// default the flags to not present
736 	*_flags = 0;
737 	*_physical = 0;
738 
739 	index = VADDR_TO_PRENT(va);
740 	if (pr[index].type != DT_ROOT) {
741 		// no pagetable here
742 		return B_NO_ERROR;
743 	}
744 
745 	do {
746 		status = get_physical_page_tmap(PRE_TO_PA(pr[index]),
747 			&pd_pg, PHYSICAL_PAGE_NO_WAIT);
748 	} while (status < B_OK);
749 	pd = (page_directory_entry *)pd_pg;
750 	// we want the table at rindex, not at rindex%(tbl/page)
751 	pd += (index % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL;
752 
753 
754 	index = VADDR_TO_PDENT(start);
755 	if (pd[index].type != DT_DIR) {
756 		// no pagetable here
757 		put_physical_page_tmap(pd_pg);
758 		return B_NO_ERROR;
759 	}
760 
761 	do {
762 		status = get_physical_page_tmap(PDE_TO_PA(pd[index]),
763 			&pt_pg, PHYSICAL_PAGE_NO_WAIT);
764 	} while (status < B_OK);
765 	pt = (page_table_entry *)pt_pg;
766 	// we want the table at rindex, not at rindex%(tbl/page)
767 	pt += (index % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL;
768 
769 	index = VADDR_TO_PTENT(va);
770 
771 	// handle indirect descriptor
772 	if (pt[index].type == DT_INDIRECT) {
773 		pi = pt;
774 		pi_pg = pt_pg;
775 		do {
776 			status = get_physical_page_tmap(PIE_TO_PA(pi[index]),
777 				&pt_pg, PHYSICAL_PAGE_NO_WAIT);
778 		} while (status < B_OK);
779 		pt = (page_table_entry *)pt_pg;
780 		// add offset from start of page
781 		pt += PIE_TO_PO(pi[index]) / sizeof(page_table_entry);
782 		// release the indirect table page
783 		put_physical_page_tmap(pi_pg);
784 	}
785 
786 	*_physical = PTE_TO_PA(pt[index]);
787 
788 	// read in the page state flags
789 	if (!pt[index].supervisor)
790 		*_flags |= (pt[index].write_protect ? 0 : B_WRITE_AREA) | B_READ_AREA;
791 
792 	*_flags |= (pt[index].write_protect ? 0 : B_KERNEL_WRITE_AREA)
793 		| B_KERNEL_READ_AREA
794 		| (pt[index].dirty ? PAGE_MODIFIED : 0)
795 		| (pt[index].accessed ? PAGE_ACCESSED : 0)
796 		| ((pt[index].type == DT_PAGE) ? PAGE_PRESENT : 0);
797 
798 	put_physical_page_tmap(pt_pg);
799 	put_physical_page_tmap(pd_pg);
800 
801 	TRACE(("query_tmap: returning pa 0x%lx for va 0x%lx\n", *_physical, va));
802 
803 	return B_OK;
804 }
805 
806 
807 static addr_t
808 get_mapped_size_tmap(vm_translation_map *map)
809 {
810 	return map->map_count;
811 }
812 
813 
814 static status_t
815 protect_tmap(vm_translation_map *map, addr_t start, addr_t end, uint32 attributes)
816 {
817 	page_table_entry *pt;
818 	page_directory_entry *pd;
819 	page_root_entry *pr = map->arch_data->rtdir_virt;
820 	addr_t pd_pg, pt_pg;
821 	status_t status;
822 	int index;
823 
824 	start = ROUNDOWN(start, B_PAGE_SIZE);
825 	end = ROUNDUP(end, B_PAGE_SIZE);
826 
827 	TRACE(("protect_tmap: pages 0x%lx to 0x%lx, attributes %lx\n", start, end, attributes));
828 
829 restart:
830 	if (start >= end)
831 		return B_OK;
832 
833 	index = VADDR_TO_PRENT(start);
834 	if (pr[index].type != DT_ROOT) {
835 		// no pagedir here, move the start up to access the next page table
836 		start = ROUNDUP(start + 1, B_PAGE_SIZE);
837 		goto restart;
838 	}
839 
840 	do {
841 		status = get_physical_page_tmap(PRE_TO_PA(pr[index]),
842 			&pd_pg, PHYSICAL_PAGE_NO_WAIT);
843 	} while (status < B_OK);
844 	pd = (page_directory_entry *)pd_pg;
845 	// we want the table at rindex, not at rindex%(tbl/page)
846 	pd += (index % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL;
847 
848 	index = VADDR_TO_PDENT(start);
849 	if (pd[index].type != DT_DIR) {
850 		// no pagetable here, move the start up to access the next page table
851 		start = ROUNDUP(start + 1, B_PAGE_SIZE);
852 		put_physical_page_tmap(pd_pg);
853 		goto restart;
854 	}
855 
856 	do {
857 		status = get_physical_page_tmap(PDE_TO_PA(pd[index]),
858 			&pt_pg, PHYSICAL_PAGE_NO_WAIT);
859 	} while (status < B_OK);
860 	pt = (page_table_entry *)pt_pg;
861 	// we want the table at rindex, not at rindex%(tbl/page)
862 	pt += (index % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL;
863 
864 	for (index = VADDR_TO_PTENT(start);
865 			(index < NUM_PAGEENT_PER_TBL) && (start < end);
866 			index++, start += B_PAGE_SIZE) {
867 		// XXX: handle indirect ?
868 		if (pt[index].type != DT_PAGE /*&& pt[index].type != DT_INDIRECT*/) {
869 			// page mapping not valid
870 			continue;
871 		}
872 
873 		TRACE(("protect_tmap: protect page 0x%lx\n", start));
874 
875 		pt[index].supervisor = (attributes & B_USER_PROTECTION) == 0;
876 		if ((attributes & B_USER_PROTECTION) != 0)
877 			pt[index].write_protect = (attributes & B_WRITE_AREA) == 0;
878 		else
879 			pt[index].write_protect = (attributes & B_KERNEL_WRITE_AREA) == 0;
880 
881 		if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE)
882 			map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = start;
883 
884 		map->arch_data->num_invalidate_pages++;
885 	}
886 
887 	put_physical_page_tmap(pt_pg);
888 	put_physical_page_tmap(pd_pg);
889 
890 	goto restart;
891 }
892 
893 
894 static status_t
895 clear_flags_tmap(vm_translation_map *map, addr_t va, uint32 flags)
896 {
897 	page_table_entry *pt;
898 	page_indirect_entry *pi;
899 	page_directory_entry *pd;
900 	page_root_entry *pr = map->arch_data->rtdir_virt;
901 	addr_t pd_pg, pt_pg, pi_pg;
902 	status_t status;
903 	int index;
904 	int tlb_flush = false;
905 
906 	index = VADDR_TO_PRENT(va);
907 	if (pr[index].type != DT_ROOT) {
908 		// no pagetable here
909 		return B_NO_ERROR;
910 	}
911 
912 	do {
913 		status = get_physical_page_tmap(PRE_TO_PA(pr[index]),
914 			&pd_pg, PHYSICAL_PAGE_NO_WAIT);
915 	} while (status < B_OK);
916 	pd = (page_directory_entry *)pd_pg;
917 	// we want the table at rindex, not at rindex%(tbl/page)
918 	pd += (index % NUM_DIRTBL_PER_PAGE) * NUM_DIRENT_PER_TBL;
919 
920 
921 	index = VADDR_TO_PDENT(start);
922 	if (pd[index].type != DT_DIR) {
923 		// no pagetable here
924 		put_physical_page_tmap(pd_pg);
925 		return B_NO_ERROR;
926 	}
927 
928 	do {
929 		status = get_physical_page_tmap(PDE_TO_PA(pd[index]),
930 			&pt_pg, PHYSICAL_PAGE_NO_WAIT);
931 	} while (status < B_OK);
932 	pt = (page_table_entry *)pt_pg;
933 	// we want the table at rindex, not at rindex%(tbl/page)
934 	pt += (index % NUM_PAGETBL_PER_PAGE) * NUM_PAGEENT_PER_TBL;
935 
936 	index = VADDR_TO_PTENT(va);
937 
938 	// handle indirect descriptor
939 	if (pt[index].type == DT_INDIRECT) {
940 		pi = pt;
941 		pi_pg = pt_pg;
942 		do {
943 			status = get_physical_page_tmap(PIE_TO_PA(pi[index]),
944 				&pt_pg, PHYSICAL_PAGE_NO_WAIT);
945 		} while (status < B_OK);
946 		pt = (page_table_entry *)pt_pg;
947 		// add offset from start of page
948 		pt += PIE_TO_PO(pi[index]) / sizeof(page_table_entry);
949 		// release the indirect table page
950 		put_physical_page_tmap(pi_pg);
951 	}
952 
953 	// clear out the flags we've been requested to clear
954 	if (flags & PAGE_MODIFIED) {
955 		pt[index].dirty = 0;
956 		tlb_flush = true;
957 	}
958 	if (flags & PAGE_ACCESSED) {
959 		pt[index].accessed = 0;
960 		tlb_flush = true;
961 	}
962 
963 	put_physical_page_tmap(pt_pg);
964 	put_physical_page_tmap(pd_pg);
965 
966 	if (tlb_flush) {
967 		if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE)
968 			map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = va;
969 
970 		map->arch_data->num_invalidate_pages++;
971 	}
972 
973 	return B_OK;
974 }
975 
976 
977 static void
978 flush_tmap(vm_translation_map *map)
979 {
980 	cpu_status state;
981 
982 	if (map->arch_data->num_invalidate_pages <= 0)
983 		return;
984 
985 	state = disable_interrupts();
986 
987 	if (map->arch_data->num_invalidate_pages > PAGE_INVALIDATE_CACHE_SIZE) {
988 		// invalidate all pages
989 		TRACE(("flush_tmap: %d pages to invalidate, invalidate all\n",
990 			map->arch_data->num_invalidate_pages));
991 
992 		if (IS_KERNEL_MAP(map)) {
993 			arch_cpu_global_TLB_invalidate();
994 			smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVALIDATE_PAGES, 0, 0, 0, NULL,
995 				SMP_MSG_FLAG_SYNC);
996 		} else {
997 			arch_cpu_user_TLB_invalidate();
998 			smp_send_broadcast_ici(SMP_MSG_USER_INVALIDATE_PAGES, 0, 0, 0, NULL,
999 				SMP_MSG_FLAG_SYNC);
1000 		}
1001 	} else {
1002 		TRACE(("flush_tmap: %d pages to invalidate, invalidate list\n",
1003 			map->arch_data->num_invalidate_pages));
1004 
1005 		arch_cpu_invalidate_TLB_list(map->arch_data->pages_to_invalidate,
1006 			map->arch_data->num_invalidate_pages);
1007 		smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_LIST,
1008 			(uint32)map->arch_data->pages_to_invalidate,
1009 			map->arch_data->num_invalidate_pages, 0, NULL,
1010 			SMP_MSG_FLAG_SYNC);
1011 	}
1012 	map->arch_data->num_invalidate_pages = 0;
1013 
1014 	restore_interrupts(state);
1015 }
1016 
1017 
1018 static status_t
1019 map_iospace_chunk(addr_t va, addr_t pa)
1020 {
1021 	int i;
1022 	page_table_entry *pt;
1023 	int state;
1024 
1025 	pa &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
1026 	va &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
1027 	if (va < sIOSpaceBase || va >= (sIOSpaceBase + IOSPACE_SIZE))
1028 		panic("map_iospace_chunk: passed invalid va 0x%lx\n", va);
1029 
1030 	pt = &iospace_pgtables[(va - sIOSpaceBase) / B_PAGE_SIZE];
1031 	for (i = 0; i < 1024; i++, pa += B_PAGE_SIZE) {
1032 		init_page_table_entry(&pt[i]);
1033 		pt[i].addr = TA_TO_PTEA(pa);
1034 		pt[i].supervisor = 1;
1035 		pt[i].write_protect = 0;
1036 		pt[i].type = DT_PAGE;
1037 		// 040 or 060 only
1038 #ifdef MMU_HAS_GLOBAL_PAGES
1039 		pt[i].global = 1;
1040 #endif
1041 	}
1042 
1043 	state = disable_interrupts();
1044 	arch_cpu_invalidate_TLB_range(va, va + (IOSPACE_CHUNK_SIZE - B_PAGE_SIZE));
1045 	smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_RANGE,
1046 		va, va + (IOSPACE_CHUNK_SIZE - B_PAGE_SIZE), 0,
1047 		NULL, SMP_MSG_FLAG_SYNC);
1048 	restore_interrupts(state);
1049 
1050 	return B_OK;
1051 }
1052 
1053 
1054 static status_t
1055 get_physical_page_tmap(addr_t pa, addr_t *va, uint32 flags)
1056 {
1057 	return generic_get_physical_page(pa, va, flags);
1058 }
1059 
1060 
1061 static status_t
1062 put_physical_page_tmap(addr_t va)
1063 {
1064 	return generic_put_physical_page(va);
1065 }
1066 
1067 
1068 static vm_translation_map_ops tmap_ops = {
1069 	destroy_tmap,
1070 	lock_tmap,
1071 	unlock_tmap,
1072 	map_max_pages_need,
1073 	map_tmap,
1074 	unmap_tmap,
1075 	query_tmap,
1076 	query_tmap_interrupt,
1077 	get_mapped_size_tmap,
1078 	protect_tmap,
1079 	clear_flags_tmap,
1080 	flush_tmap,
1081 	get_physical_page_tmap,
1082 	put_physical_page_tmap
1083 };
1084 
1085 
1086 //	#pragma mark -
1087 //	VM API
1088 
1089 
1090 static status_t
1091 arch_vm_translation_map_init_map(vm_translation_map *map, bool kernel)
1092 {
1093 	if (map == NULL)
1094 		return B_BAD_VALUE;
1095 
1096 	TRACE(("vm_translation_map_create\n"));
1097 
1098 	// initialize the new object
1099 	map->ops = &tmap_ops;
1100 	map->map_count = 0;
1101 
1102 	if (!kernel) {
1103 		// During the boot process, there are no semaphores available at this
1104 		// point, so we only try to create the translation map lock if we're
1105 		// initialize a user translation map.
1106 		// vm_translation_map_init_kernel_map_post_sem() is used to complete
1107 		// the kernel translation map.
1108 		if (recursive_lock_init(&map->lock, "translation map") < B_OK)
1109 			return map->lock.sem;
1110 	}
1111 
1112 	map->arch_data = (vm_translation_map_arch_info *)malloc(sizeof(vm_translation_map_arch_info));
1113 	if (map == NULL) {
1114 		recursive_lock_destroy(&map->lock);
1115 		return B_NO_MEMORY;
1116 	}
1117 
1118 	map->arch_data->num_invalidate_pages = 0;
1119 
1120 	if (!kernel) {
1121 		// user
1122 		// allocate a rtdir
1123 		map->arch_data->rtdir_virt = (page_root_entry *)memalign(
1124 			SIZ_ROOTTBL, SIZ_ROOTTBL);
1125 		if (map->arch_data->rtdir_virt == NULL) {
1126 			free(map->arch_data);
1127 			recursive_lock_destroy(&map->lock);
1128 			return B_NO_MEMORY;
1129 		}
1130 		vm_get_page_mapping(vm_kernel_address_space_id(),
1131 			(addr_t)map->arch_data->rtdir_virt, (addr_t *)&map->arch_data->rtdir_phys);
1132 	} else {
1133 		// kernel
1134 		// we already know the kernel pgdir mapping
1135 		map->arch_data->rtdir_virt = sKernelVirtualPageRoot;
1136 		map->arch_data->rtdir_phys = sKernelPhysicalPageRoot;
1137 	}
1138 
1139 	// zero out the bottom portion of the new rtdir
1140 	memset(map->arch_data->rtdir_virt + FIRST_USER_PGROOT_ENT, 0,
1141 		NUM_USER_PGROOT_ENTS * sizeof(page_root_entry));
1142 
1143 	// insert this new map into the map list
1144 	{
1145 		int state = disable_interrupts();
1146 		acquire_spinlock(&tmap_list_lock);
1147 
1148 		// copy the top portion of the rtdir from the current one
1149 		memcpy(map->arch_data->rtdir_virt + FIRST_KERNEL_PGROOT_ENT,
1150 			sKernelVirtualPageRoot + FIRST_KERNEL_PGROOT_ENT,
1151 			NUM_KERNEL_PGROOT_ENTS * sizeof(page_root_entry));
1152 
1153 		map->next = tmap_list;
1154 		tmap_list = map;
1155 
1156 		release_spinlock(&tmap_list_lock);
1157 		restore_interrupts(state);
1158 	}
1159 
1160 	return B_OK;
1161 }
1162 
1163 
1164 static status_t
1165 arch_vm_translation_map_init_kernel_map_post_sem(vm_translation_map *map)
1166 {
1167 	if (recursive_lock_init(&map->lock, "translation map") < B_OK)
1168 		return map->lock.sem;
1169 
1170 	return B_OK;
1171 }
1172 
1173 
1174 static status_t
1175 arch_vm_translation_map_init(kernel_args *args)
1176 {
1177 	status_t error;
1178 
1179 	TRACE(("vm_translation_map_init: entry\n"));
1180 #if 0
1181 	// page hole set up in stage2
1182 	page_hole = (page_table_entry *)args->arch_args.page_hole;
1183 	// calculate where the pgdir would be
1184 	page_hole_pgdir = (page_directory_entry *)(((unsigned int)args->arch_args.page_hole) + (B_PAGE_SIZE * 1024 - B_PAGE_SIZE));
1185 	// clear out the bottom 2 GB, unmap everything
1186 	memset(page_hole_pgdir + FIRST_USER_PGDIR_ENT, 0, sizeof(page_directory_entry) * NUM_USER_PGDIR_ENTS);
1187 #endif
1188 
1189 	sKernelPhysicalPageRoot = (page_root_entry *)args->arch_args.phys_pgroot;
1190 	sKernelVirtualPageRoot = (page_root_entry *)args->arch_args.vir_pgroot;
1191 
1192 	sQueryDesc.type = DT_INVALID;
1193 
1194 	tmap_list_lock = 0;
1195 	tmap_list = NULL;
1196 
1197 	// allocate some space to hold physical page mapping info
1198 	//XXX: check page count
1199 #error XXXXXXXXXXXX pt + pd? pd = memalign ?
1200 	iospace_pgtables = (page_table_entry *)vm_allocate_early(args,
1201 		B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * NUM_PAGEENT_PER_TBL * NUM_PAGETBL_PER_PAGE)), ~0L,
1202 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
1203 
1204 	TRACE(("iospace_pgtables %p\n", iospace_pgtables));
1205 
1206 	// init physical page mapper
1207 	error = generic_vm_physical_page_mapper_init(args, map_iospace_chunk,
1208 		&sIOSpaceBase, IOSPACE_SIZE, IOSPACE_CHUNK_SIZE);
1209 	if (error != B_OK)
1210 		return error;
1211 
1212 	// initialize our data structures
1213 	memset(iospace_pgtables, 0, B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)));
1214 
1215 	TRACE(("mapping iospace_pgtables\n"));
1216 
1217 	// put the array of pgtables directly into the kernel pagedir
1218 	// these will be wired and kept mapped into virtual space to be easy to get to
1219 	{
1220 #error XXXXXXXXXXXX
1221 		addr_t phys_pgtable;
1222 		addr_t virt_pgtable;
1223 		page_directory_entry *e;
1224 		int i;
1225 
1226 		virt_pgtable = (addr_t)iospace_pgtables;
1227 		for (i = 0; i < (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)); i++, virt_pgtable += B_PAGE_SIZE) {
1228 			early_query(virt_pgtable, &phys_pgtable);
1229 			e = &page_hole_pgdir[(sIOSpaceBase / (B_PAGE_SIZE * 1024)) + i];
1230 			put_pgtable_in_pgdir(e, phys_pgtable, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
1231 		}
1232 	}
1233 
1234 	TRACE(("vm_translation_map_init: done\n"));
1235 
1236 	return B_OK;
1237 }
1238 
1239 
1240 static status_t
1241 arch_vm_translation_map_init_post_sem(kernel_args *args)
1242 {
1243 	return generic_vm_physical_page_mapper_init_post_sem(args);
1244 }
1245 
1246 
1247 static status_t
1248 arch_vm_translation_map_init_post_area(kernel_args *args)
1249 {
1250 	// now that the vm is initialized, create a region that represents
1251 	// the page hole
1252 	void *temp;
1253 	status_t error;
1254 	area_id area;
1255 	void *queryPage;
1256 
1257 	TRACE(("vm_translation_map_init_post_area: entry\n"));
1258 
1259 	// unmap the page hole hack we were using before
1260 	sKernelVirtualPageRoot[1023].present = 0;
1261 	page_hole_pgdir = NULL;
1262 	page_hole = NULL;
1263 
1264 	temp = (void *)sKernelVirtualPageRoot;
1265 	area = create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, B_PAGE_SIZE,
1266 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
1267 	if (area < B_OK)
1268 		return area;
1269 
1270 	temp = (void *)iospace_pgtables;
1271 	area = create_area("iospace_pgtables", &temp, B_EXACT_ADDRESS,
1272 		B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)),
1273 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
1274 	if (area < B_OK)
1275 		return area;
1276 
1277 	error = generic_vm_physical_page_mapper_init_post_area(args);
1278 	if (error != B_OK)
1279 		return error;
1280 
1281 	// this area is used for query_tmap_interrupt()
1282 	// TODO: Note, this only works as long as all pages belong to the same
1283 	//	page table, which is not yet enforced (or even tested)!
1284 	// Note we don't support SMP which makes things simpler.
1285 
1286 	area = vm_create_null_area(vm_kernel_address_space_id(),
1287 		"interrupt query pages", (void **)&queryPage, B_ANY_ADDRESS,
1288 		B_PAGE_SIZE);
1289 	if (area < B_OK)
1290 		return area;
1291 
1292 	// insert the indirect descriptor in the tree so we can map the page we want from it.
1293 
1294 	{
1295 		page_directory_entry *pageDirEntry;
1296 		page_indirect_entry *pageTableEntry;
1297 		addr_t physicalPageDir, physicalPageTable;
1298 		addr_t physicalIndirectDesc;
1299 		int32 index;
1300 
1301 		// first get pa for the indirect descriptor
1302 
1303 		index = VADDR_TO_PRENT((addr_t)&sQueryDesc);
1304 		physicalPageDir = PRE_TO_PA(sKernelVirtualPageRoot[index]);
1305 
1306 		get_physical_page_tmap(physicalPageDir,
1307 			(addr_t *)&pageDirEntry, PHYSICAL_PAGE_NO_WAIT);
1308 
1309 		index = VADDR_TO_PDENT((addr_t)&sQueryDesc);
1310 		physicalPageTable = PDE_TO_PA(pageDirEntry[index]);
1311 
1312 		get_physical_page_tmap(physicalPageTable,
1313 			(addr_t *)&pageTableEntry, PHYSICAL_PAGE_NO_WAIT);
1314 
1315 		index = VADDR_TO_PTENT((addr_t)&sQueryDesc);
1316 
1317 		// pa of the page
1318 		physicalIndirectDesc = PTE_TO_PA(pageTableEntry[index]);
1319 		// add offset
1320 		physicalIndirectDesc += ((addr_t)&sQueryDesc) % B_PAGE_SIZE;
1321 
1322 		put_physical_page_tmap((addr_t)pageTableEntry);
1323 		put_physical_page_tmap((addr_t)pageDirEntry);
1324 
1325 		// then the va for the page table for the query page.
1326 
1327 		//sQueryPageTable = (page_indirect_entry *)(queryPage);
1328 
1329 		index = VADDR_TO_PRENT((addr_t)queryPage);
1330 		physicalPageDir = PRE_TO_PA(sKernelVirtualPageRoot[index]);
1331 
1332 		get_physical_page_tmap(physicalPageDir,
1333 			(addr_t *)&pageDirEntry, PHYSICAL_PAGE_NO_WAIT);
1334 
1335 		index = VADDR_TO_PDENT((addr_t)queryPage);
1336 		physicalPageTable = PDE_TO_PA(pageDirEntry[index]);
1337 
1338 		get_physical_page_tmap(physicalPageTable,
1339 			(addr_t *)&pageTableEntry, PHYSICAL_PAGE_NO_WAIT);
1340 
1341 		index = VADDR_TO_PTENT((addr_t)queryPage);
1342 
1343 		put_page_indirect_entry_in_pgtable(&pageTableEntry[index], physicalIndirectDesc,
1344 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, false);
1345 
1346 		put_physical_page_tmap((addr_t)pageTableEntry);
1347 		put_physical_page_tmap((addr_t)pageDirEntry);
1348 		//invalidate_TLB(sQueryPageTable);
1349 	}
1350 	// qmery_tmap_interrupt checks for the NULL, now it can use it
1351 	sQueryPage = queryPage;
1352 
1353 	TRACE(("vm_translation_map_init_post_area: done\n"));
1354 	return B_OK;
1355 }
1356 
1357 
1358 // XXX horrible back door to map a page quickly regardless of translation map object, etc.
1359 // used only during VM setup.
1360 // uses a 'page hole' set up in the stage 2 bootloader. The page hole is created by pointing one of
1361 // the pgdir entries back at itself, effectively mapping the contents of all of the 4MB of pagetables
1362 // into a 4 MB region. It's only used here, and is later unmapped.
1363 
1364 static status_t
1365 arch_vm_translation_map_early_map(kernel_args *args, addr_t va, addr_t pa,
1366 	uint8 attributes, addr_t (*get_free_page)(kernel_args *))
1367 {
1368 	int index;
1369 
1370 	TRACE(("early_tmap: entry pa 0x%lx va 0x%lx\n", pa, va));
1371 
1372 	// check to see if a page table exists for this range
1373 	index = VADDR_TO_PDENT(va);
1374 	if (page_hole_pgdir[index].present == 0) {
1375 		addr_t pgtable;
1376 		page_directory_entry *e;
1377 		// we need to allocate a pgtable
1378 		pgtable = get_free_page(args);
1379 		// pgtable is in pages, convert to physical address
1380 		pgtable *= B_PAGE_SIZE;
1381 
1382 		TRACE(("early_map: asked for free page for pgtable. 0x%lx\n", pgtable));
1383 
1384 		// put it in the pgdir
1385 		e = &page_hole_pgdir[index];
1386 		put_pgtable_in_pgdir(e, pgtable, attributes);
1387 
1388 		// zero it out in it's new mapping
1389 		memset((unsigned int *)((unsigned int)page_hole + (va / B_PAGE_SIZE / 1024) * B_PAGE_SIZE), 0, B_PAGE_SIZE);
1390 	}
1391 
1392 	// now, fill in the pentry
1393 	put_page_table_entry_in_pgtable(page_hole + va / B_PAGE_SIZE, pa, attributes,
1394 		IS_KERNEL_ADDRESS(va));
1395 
1396 	arch_cpu_invalidate_TLB_range(va, va);
1397 
1398 	return B_OK;
1399 }
1400 
1401