FreeBSD/sys/arm/arm/pmap-v6.c
/*
 *	The fundamental initialization of PMAP stuff.
 *
 *  Some things already happened in locore.S and some things could happen
 *  before pmap_bootstrap_prepare() is called, so let's recall what is done:
 *  1. Caches are disabled.
 *  2. We are running on virtual addresses already with 'boot_pt1'
 *     as L1 page table.
 *  3. So far, all virtual addresses can be converted to physical ones and
 *     vice versa by the following macros:
 *       KERNEL_P2V(pa) .... physical to virtual ones,
 *       KERNEL_V2P(va) .... virtual to physical ones.
 *
 *  What is done herein:
 *  1. The 'boot_pt1' is replaced by real kernel L1 page table 'kern_pt1'.
 *  2. PT2MAP magic is brought to live.
 *  3. Basic preboot functions for page allocations and mappings can be used.
 *  4. Everything is prepared for L1 cache enabling.
 *
 *  Variations:
 *  1. To use second TTB register, so kernel and users page tables will be
 *     separated. This way process forking - pmap_pinit() - could be faster,
 *     it saves physical pages and KVA per a process, and it's simple change.
 *     However, it will lead, due to hardware matter, to the following:
 *     (a) 2G space for kernel and 2G space for users.
 *     (b) 1G space for kernel in low addresses and 3G for users above it.
 *     A question is: Is the case (b) really an option? Note that case (b)
 *     does save neither physical memory and KVA.
 */
The fundamental initialization of PMAP stuff.
Some things already happened in locore.S and some things could happen
before pmap_bootstrap_prepare() is called, so let's recall what is done:
1. Caches are disabled.
2. We are running on virtual addresses already with 'boot_pt1'
as L1 page table.
3. So far, all virtual addresses can be converted to physical ones and
vice versa by the following macros:
KERNEL_P2V(pa) .... physical to virtual ones,
KERNEL_V2P(va) .... virtual to physical ones.



1. To use second TTB register, so kernel and users page tables will be
separated. This way process forking - pmap_pinit() - could be faster,
it saves physical pages and KVA per a process, and it's simple change.
However, it will lead, due to hardware matter, to the following:
(a) 2G space for kernel and 2G space for users.
(b) 1G space for kernel in low addresses and 3G for users above it.
A question is: Is the case (b) really an option. Note that case (b)
does save neither physical memory and KVA.
The fundamental initialization of PMAP stuff . Some things already happened in locore . S and some things could happen before pmap_bootstrap_prepare () is called so let ' s recall what is done : 1 . Caches are disabled . 2 . We are running on virtual addresses already with ' boot_pt1 ' as L1 page table . 3 . So far all virtual addresses can be converted to physical ones and vice versa by the following macros : KERNEL_P2V ( pa ) .... physical to virtual ones KERNEL_V2P ( va ) .... virtual to physical ones . 1 . To use second TTB register so kernel and users page tables will be separated . This way process forking - pmap_pinit () - could be faster it saves physical pages and KVA per a process and it ' s simple change . However it will lead due to hardware matter to the following : ( a ) 2G space for kernel and 2G space for users . ( b ) 1G space for kernel in low addresses and 3G for users above it . A question is : Is the case ( b ) really an option . Note that case ( b ) does save neither physical memory and KVA .
void
pmap_bootstrap_prepare(vm_paddr_t last)
{
	vm_paddr_t pt2pg_pa, pt2tab_pa, pa, size;
	vm_offset_t pt2pg_va;
	pt1_entry_t *pte1p;
	pt2_entry_t *pte2p;
	u_int i;
	uint32_t actlr_mask, actlr_set, l1_attr;
	last_paddr = pte1_roundup(last);
	base_pt1 = pmap_preboot_get_pages(NPG_IN_PT1);
	kern_pt1 = (pt1_entry_t *)KERNEL_P2V(base_pt1);
	bzero((void*)kern_pt1, NB_IN_PT1);
	pte1_sync_range(kern_pt1, NB_IN_PT1);
	pt2tab_pa = pmap_preboot_get_pages(NPG_IN_PT2TAB);
	kern_pt2tab = (pt2_entry_t *)KERNEL_P2V(pt2tab_pa);
	bzero(kern_pt2tab, NB_IN_PT2TAB);
	pte2_sync_range(kern_pt2tab, NB_IN_PT2TAB);
	pt2pg_pa = pmap_preboot_get_pages(NKPT2PG);
	pt2pg_va = KERNEL_P2V(pt2pg_pa);
	size = NKPT2PG * PAGE_SIZE;
	bzero((void*)pt2pg_va, size);
	pte2_sync_range((pt2_entry_t *)pt2pg_va, size);
	vm_phys_add_seg(pt2tab_pa, pmap_preboot_get_pages(0));
	pte2p = kern_pt2tab_entry(KERNBASE);
	for (pa = pt2pg_pa; pa < pt2pg_pa + size; pa += PTE2_SIZE)
		pt2tab_store(pte2p++, PTE2_KPT(pa));
	pte1p = kern_pte1(KERNBASE);
	for (pa = pt2pg_pa; pa < pt2pg_pa + size; pa += NB_IN_PT2)
		pte1_store(pte1p++, PTE1_LINK(pa));
	l1_attr = ATTR_TO_L1(PTE2_ATTR_DEFAULT);
	pte1p = kern_pte1(KERNBASE);
	for (pa = KERNEL_V2P(KERNBASE); pa < last; pa += PTE1_SIZE)
		pte1_store(pte1p++, PTE1_KERN(pa, PTE1_AP_KRW, l1_attr));
	PT2MAP = (pt2_entry_t *)(KERNBASE - PT2MAP_SIZE);
	pte1p = kern_pte1((vm_offset_t)PT2MAP);
	for (pa = pt2tab_pa, i = 0; i < NPT2_IN_PT2TAB; i++, pa += NB_IN_PT2) {
		pte1_store(pte1p++, PTE1_LINK(pa));
	}
	pte2p = kern_pt2tab_entry((vm_offset_t)PT2MAP);
	for (pa = pt2tab_pa, i = 0; i < NPG_IN_PT2TAB; i++, pa += PTE2_SIZE) {
		pt2tab_store(pte2p++, PTE2_KPT_NG(pa));
	}
	pte2p = kern_pt2tab_entry((vm_offset_t)kern_pt1);
	pt2pg_va = KERNEL_P2V(pte2_pa(pte2_load(pte2p)));
	pte2p = page_pt2(pt2pg_va, pte1_index((vm_offset_t)kern_pt1));
	for (pa = base_pt1, i = 0; i < NPG_IN_PT1; i++, pa += PTE2_SIZE)
		pte2_store(pte2p++, PTE2_KPT(pa));
	for (pa = pt2tab_pa, i = 0; i < NPG_IN_PT2TAB; i++, pa += PTE2_SIZE)
		pte2_store(pte2p++, PTE2_KPT(pa));
	pmap_kern_ttb = base_pt1 | ttb_flags;
	cpuinfo_get_actlr_modifier(&actlr_mask, &actlr_set);
	reinit_mmu(pmap_kern_ttb, actlr_mask, actlr_set);
	virtual_avail = (vm_offset_t)kern_pt2tab + NPG_IN_PT2TAB * PAGE_SIZE;
}
void pmap_bootstrap_prepare ( vm_paddr_t last ) { vm_paddr_t pt2pg_pa , pt2tab_pa , pa , size ; vm_offset_t pt2pg_va ; pt1_entry_t * pte1p ; pt2_entry_t * pte2p ; u_int i ; uint32_t actlr_mask , actlr_set , l1_attr ; last_paddr = pte1_roundup ( last ) ; base_pt1 = pmap_preboot_get_pages ( NPG_IN_PT1 ) ; kern_pt1 = ( pt1_entry_t * ) KERNEL_P2V ( base_pt1 ) ; bzero ( ( void * ) kern_pt1 , NB_IN_PT1 ) ; pte1_sync_range ( kern_pt1 , NB_IN_PT1 ) ; pt2tab_pa = pmap_preboot_get_pages ( NPG_IN_PT2TAB ) ; kern_pt2tab = ( pt2_entry_t * ) KERNEL_P2V ( pt2tab_pa ) ; bzero ( kern_pt2tab , NB_IN_PT2TAB ) ; pte2_sync_range ( kern_pt2tab , NB_IN_PT2TAB ) ; pt2pg_pa = pmap_preboot_get_pages ( NKPT2PG ) ; pt2pg_va = KERNEL_P2V ( pt2pg_pa ) ; size = NKPT2PG * PAGE_SIZE ; bzero ( ( void * ) pt2pg_va , size ) ; pte2_sync_range ( ( pt2_entry_t * ) pt2pg_va , size ) ; vm_phys_add_seg ( pt2tab_pa , pmap_preboot_get_pages ( 0 ) ) ; pte2p = kern_pt2tab_entry ( KERNBASE ) ; for ( pa = pt2pg_pa ; pa < pt2pg_pa + size ; pa += PTE2_SIZE ) pt2tab_store ( pte2p ++ , PTE2_KPT ( pa ) ) ; pte1p = kern_pte1 ( KERNBASE ) ; for ( pa = pt2pg_pa ; pa < pt2pg_pa + size ; pa += NB_IN_PT2 ) pte1_store ( pte1p ++ , PTE1_LINK ( pa ) ) ; l1_attr = ATTR_TO_L1 ( PTE2_ATTR_DEFAULT ) ; pte1p = kern_pte1 ( KERNBASE ) ; for ( pa = KERNEL_V2P ( KERNBASE ) ; pa < last ; pa += PTE1_SIZE ) pte1_store ( pte1p ++ , PTE1_KERN ( pa , PTE1_AP_KRW , l1_attr ) ) ; PT2MAP = ( pt2_entry_t * ) ( KERNBASE - PT2MAP_SIZE ) ; pte1p = kern_pte1 ( ( vm_offset_t ) PT2MAP ) ; for ( pa = pt2tab_pa , i = 0 ; i < NPT2_IN_PT2TAB ; i ++ , pa += NB_IN_PT2 ) { pte1_store ( pte1p ++ , PTE1_LINK ( pa ) ) ; } pte2p = kern_pt2tab_entry ( ( vm_offset_t ) PT2MAP ) ; for ( pa = pt2tab_pa , i = 0 ; i < NPG_IN_PT2TAB ; i ++ , pa += PTE2_SIZE ) { pt2tab_store ( pte2p ++ , PTE2_KPT_NG ( pa ) ) ; } pte2p = kern_pt2tab_entry ( ( vm_offset_t ) kern_pt1 ) ; pt2pg_va = KERNEL_P2V ( pte2_pa ( pte2_load ( pte2p ) ) ) ; pte2p = page_pt2 ( pt2pg_va , pte1_index ( ( vm_offset_t ) kern_pt1 ) ) ; for ( pa = base_pt1 , i = 0 ; i < NPG_IN_PT1 ; i ++ , pa += PTE2_SIZE ) pte2_store ( pte2p ++ , PTE2_KPT ( pa ) ) ; for ( pa = pt2tab_pa , i = 0 ; i < NPG_IN_PT2TAB ; i ++ , pa += PTE2_SIZE ) pte2_store ( pte2p ++ , PTE2_KPT ( pa ) ) ; pmap_kern_ttb = base_pt1 | ttb_flags ; cpuinfo_get_actlr_modifier ( & actlr_mask , & actlr_set ) ; reinit_mmu ( pmap_kern_ttb , actlr_mask , actlr_set ) ; virtual_avail = ( vm_offset_t ) kern_pt2tab + NPG_IN_PT2TAB * PAGE_SIZE ; }
The fundamental initialization of PMAP stuff.
The fundamental initialization of PMAP stuff .
/*
	 * Now, we are going to make real kernel mapping. Note that we are
	 * already running on some mapping made in locore.S and we expect
	 * that it's large enough to ensure nofault access to physical memory
	 * allocated herein before switch.
	 *
	 * As kernel image and everything needed before are and will be mapped
	 * by section mappings, we align last physical address to PTE1_SIZE.
	 */ /*
	 * Allocate and zero page(s) for kernel L1 page table.
	 *
	 * Note that it's first allocation on space which was PTE1_SIZE
	 * aligned and as such base_pt1 is aligned to NB_IN_PT1 too.
	 */ /* Allocate and zero page(s) for kernel PT2TAB. */ /* Allocate and zero page(s) for kernel L2 page tables. */ /*
	 * Add a physical memory segment (vm_phys_seg) corresponding to the
	 * preallocated pages for kernel L2 page tables so that vm_page
	 * structures representing these pages will be created. The vm_page
	 * structures are required for promotion of the corresponding kernel
	 * virtual addresses to section mappings.
	 */ /*
	 * Insert allocated L2 page table pages to PT2TAB and make
	 * link to all PT2s in L1 page table. See how kernel_vm_end
	 * is initialized.
	 *
	 * We play simple and safe. So every KVA will have underlaying
	 * L2 page table, even kernel image mapped by sections.
	 */ /* Make section mappings for kernel. */ /*
	 * Get free and aligned space for PT2MAP and make L1 page table links
	 * to L2 page tables held in PT2TAB.
	 *
	 * Note that pages holding PT2s are stored in PT2TAB as pt2_entry_t
	 * descriptors and PT2TAB page(s) itself is(are) used as PT2s. Thus
	 * each entry in PT2TAB maps all PT2s in a page. This implies that
	 * virtual address of PT2MAP must be aligned to NPT2_IN_PG * PTE1_SIZE.
	 */ /*
	 * Store PT2TAB in PT2TAB itself, i.e. self reference mapping.
	 * Each pmap will hold own PT2TAB, so the mapping should be not global.
	 */ /*
	 * Choose correct L2 page table and make mappings for allocations
	 * made herein which replaces temporary locore.S mappings after a while.
	 * Note that PT2MAP cannot be used until we switch to kern_pt1.
	 *
	 * Note, that these allocations started aligned on 1M section and
	 * kernel PT1 was allocated first. Making of mappings must follow
	 * order of physical allocations as we've used KERNEL_P2V() macro
	 * for virtual addresses resolution.
	 */ /* Make mapping for kernel L1 page table. */ /* Make mapping for kernel PT2TAB. */ /* Finally, switch from 'boot_pt1' to 'kern_pt1'. */ /*
	 * Initialize the first available KVA. As kernel image is mapped by
	 * sections, we are leaving some gap behind.
	 */