Home | History | Annotate | Line # | Download | only in prekern
mm.c revision 1.20.2.2
      1  1.20.2.2  jdolecek /*	$NetBSD: mm.c,v 1.20.2.2 2017/12/03 11:35:48 jdolecek Exp $	*/
      2  1.20.2.2  jdolecek 
      3  1.20.2.2  jdolecek /*
      4  1.20.2.2  jdolecek  * Copyright (c) 2017 The NetBSD Foundation, Inc. All rights reserved.
      5  1.20.2.2  jdolecek  *
      6  1.20.2.2  jdolecek  * This code is derived from software contributed to The NetBSD Foundation
      7  1.20.2.2  jdolecek  * by Maxime Villard.
      8  1.20.2.2  jdolecek  *
      9  1.20.2.2  jdolecek  * Redistribution and use in source and binary forms, with or without
     10  1.20.2.2  jdolecek  * modification, are permitted provided that the following conditions
     11  1.20.2.2  jdolecek  * are met:
     12  1.20.2.2  jdolecek  * 1. Redistributions of source code must retain the above copyright
     13  1.20.2.2  jdolecek  *    notice, this list of conditions and the following disclaimer.
     14  1.20.2.2  jdolecek  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.20.2.2  jdolecek  *    notice, this list of conditions and the following disclaimer in the
     16  1.20.2.2  jdolecek  *    documentation and/or other materials provided with the distribution.
     17  1.20.2.2  jdolecek  *
     18  1.20.2.2  jdolecek  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  1.20.2.2  jdolecek  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  1.20.2.2  jdolecek  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  1.20.2.2  jdolecek  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  1.20.2.2  jdolecek  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  1.20.2.2  jdolecek  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  1.20.2.2  jdolecek  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  1.20.2.2  jdolecek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  1.20.2.2  jdolecek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  1.20.2.2  jdolecek  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  1.20.2.2  jdolecek  * POSSIBILITY OF SUCH DAMAGE.
     29  1.20.2.2  jdolecek  */
     30  1.20.2.2  jdolecek 
     31  1.20.2.2  jdolecek #include "prekern.h"
     32  1.20.2.2  jdolecek 
     33  1.20.2.2  jdolecek #define PAD_TEXT	0xCC
     34  1.20.2.2  jdolecek #define PAD_RODATA	0x00
     35  1.20.2.2  jdolecek #define PAD_DATA	0x00
     36  1.20.2.2  jdolecek 
     37  1.20.2.2  jdolecek #define ELFROUND	64
     38  1.20.2.2  jdolecek 
     39  1.20.2.2  jdolecek static const uint8_t pads[4] = {
     40  1.20.2.2  jdolecek 	[BTSEG_NONE] = 0x00,
     41  1.20.2.2  jdolecek 	[BTSEG_TEXT] = 0xCC,
     42  1.20.2.2  jdolecek 	[BTSEG_RODATA] = 0x00,
     43  1.20.2.2  jdolecek 	[BTSEG_DATA] = 0x00
     44  1.20.2.2  jdolecek };
     45  1.20.2.2  jdolecek 
     46  1.20.2.2  jdolecek #define MM_PROT_READ	0x00
     47  1.20.2.2  jdolecek #define MM_PROT_WRITE	0x01
     48  1.20.2.2  jdolecek #define MM_PROT_EXECUTE	0x02
     49  1.20.2.2  jdolecek 
     50  1.20.2.2  jdolecek static const pt_entry_t protection_codes[3] = {
     51  1.20.2.2  jdolecek 	[MM_PROT_READ] = PG_RO | PG_NX,
     52  1.20.2.2  jdolecek 	[MM_PROT_WRITE] = PG_RW | PG_NX,
     53  1.20.2.2  jdolecek 	[MM_PROT_EXECUTE] = PG_RO,
     54  1.20.2.2  jdolecek 	/* RWX does not exist */
     55  1.20.2.2  jdolecek };
     56  1.20.2.2  jdolecek 
     57  1.20.2.2  jdolecek struct bootspace bootspace;
     58  1.20.2.2  jdolecek 
     59  1.20.2.2  jdolecek extern paddr_t kernpa_start, kernpa_end;
     60  1.20.2.2  jdolecek vaddr_t iom_base;
     61  1.20.2.2  jdolecek 
     62  1.20.2.2  jdolecek paddr_t pa_avail = 0;
     63  1.20.2.2  jdolecek static const vaddr_t tmpva = (PREKERNBASE + NKL2_KIMG_ENTRIES * NBPD_L2);
     64  1.20.2.2  jdolecek 
     65  1.20.2.2  jdolecek void
     66  1.20.2.2  jdolecek mm_init(paddr_t first_pa)
     67  1.20.2.2  jdolecek {
     68  1.20.2.2  jdolecek 	pa_avail = first_pa;
     69  1.20.2.2  jdolecek }
     70  1.20.2.2  jdolecek 
     71  1.20.2.2  jdolecek static void
     72  1.20.2.2  jdolecek mm_enter_pa(paddr_t pa, vaddr_t va, pte_prot_t prot)
     73  1.20.2.2  jdolecek {
     74  1.20.2.2  jdolecek 	if (PTE_BASE[pl1_i(va)] & PG_V) {
     75  1.20.2.2  jdolecek 		fatal("mm_enter_pa: mapping already present");
     76  1.20.2.2  jdolecek 	}
     77  1.20.2.2  jdolecek 	PTE_BASE[pl1_i(va)] = pa | PG_V | protection_codes[prot];
     78  1.20.2.2  jdolecek }
     79  1.20.2.2  jdolecek 
     80  1.20.2.2  jdolecek static void
     81  1.20.2.2  jdolecek mm_reenter_pa(paddr_t pa, vaddr_t va, pte_prot_t prot)
     82  1.20.2.2  jdolecek {
     83  1.20.2.2  jdolecek 	PTE_BASE[pl1_i(va)] = pa | PG_V | protection_codes[prot];
     84  1.20.2.2  jdolecek }
     85  1.20.2.2  jdolecek 
     86  1.20.2.2  jdolecek static void
     87  1.20.2.2  jdolecek mm_flush_va(vaddr_t va)
     88  1.20.2.2  jdolecek {
     89  1.20.2.2  jdolecek 	asm volatile("invlpg (%0)" ::"r" (va) : "memory");
     90  1.20.2.2  jdolecek }
     91  1.20.2.2  jdolecek 
     92  1.20.2.2  jdolecek static paddr_t
     93  1.20.2.2  jdolecek mm_palloc(size_t npages)
     94  1.20.2.2  jdolecek {
     95  1.20.2.2  jdolecek 	paddr_t pa;
     96  1.20.2.2  jdolecek 	size_t i;
     97  1.20.2.2  jdolecek 
     98  1.20.2.2  jdolecek 	/* Allocate the physical pages */
     99  1.20.2.2  jdolecek 	pa = pa_avail;
    100  1.20.2.2  jdolecek 	pa_avail += npages * PAGE_SIZE;
    101  1.20.2.2  jdolecek 
    102  1.20.2.2  jdolecek 	/* Zero them out */
    103  1.20.2.2  jdolecek 	for (i = 0; i < npages; i++) {
    104  1.20.2.2  jdolecek 		mm_reenter_pa(pa + i * PAGE_SIZE, tmpva,
    105  1.20.2.2  jdolecek 		    MM_PROT_READ|MM_PROT_WRITE);
    106  1.20.2.2  jdolecek 		mm_flush_va(tmpva);
    107  1.20.2.2  jdolecek 		memset((void *)tmpva, 0, PAGE_SIZE);
    108  1.20.2.2  jdolecek 	}
    109  1.20.2.2  jdolecek 
    110  1.20.2.2  jdolecek 	return pa;
    111  1.20.2.2  jdolecek }
    112  1.20.2.2  jdolecek 
    113  1.20.2.2  jdolecek static bool
    114  1.20.2.2  jdolecek mm_pte_is_valid(pt_entry_t pte)
    115  1.20.2.2  jdolecek {
    116  1.20.2.2  jdolecek 	return ((pte & PG_V) != 0);
    117  1.20.2.2  jdolecek }
    118  1.20.2.2  jdolecek 
    119  1.20.2.2  jdolecek static void
    120  1.20.2.2  jdolecek mm_mprotect(vaddr_t startva, size_t size, pte_prot_t prot)
    121  1.20.2.2  jdolecek {
    122  1.20.2.2  jdolecek 	size_t i, npages;
    123  1.20.2.2  jdolecek 	vaddr_t va;
    124  1.20.2.2  jdolecek 	paddr_t pa;
    125  1.20.2.2  jdolecek 
    126  1.20.2.2  jdolecek 	ASSERT(size % PAGE_SIZE == 0);
    127  1.20.2.2  jdolecek 	npages = size / PAGE_SIZE;
    128  1.20.2.2  jdolecek 
    129  1.20.2.2  jdolecek 	for (i = 0; i < npages; i++) {
    130  1.20.2.2  jdolecek 		va = startva + i * PAGE_SIZE;
    131  1.20.2.2  jdolecek 		pa = (PTE_BASE[pl1_i(va)] & PG_FRAME);
    132  1.20.2.2  jdolecek 		mm_reenter_pa(pa, va, prot);
    133  1.20.2.2  jdolecek 		mm_flush_va(va);
    134  1.20.2.2  jdolecek 	}
    135  1.20.2.2  jdolecek }
    136  1.20.2.2  jdolecek 
    137  1.20.2.2  jdolecek void
    138  1.20.2.2  jdolecek mm_bootspace_mprotect(void)
    139  1.20.2.2  jdolecek {
    140  1.20.2.2  jdolecek 	pte_prot_t prot;
    141  1.20.2.2  jdolecek 	size_t i;
    142  1.20.2.2  jdolecek 
    143  1.20.2.2  jdolecek 	/* Remap the kernel segments with proper permissions. */
    144  1.20.2.2  jdolecek 	for (i = 0; i < BTSPACE_NSEGS; i++) {
    145  1.20.2.2  jdolecek 		if (bootspace.segs[i].type == BTSEG_TEXT) {
    146  1.20.2.2  jdolecek 			prot = MM_PROT_READ|MM_PROT_EXECUTE;
    147  1.20.2.2  jdolecek 		} else if (bootspace.segs[i].type == BTSEG_RODATA) {
    148  1.20.2.2  jdolecek 			prot = MM_PROT_READ;
    149  1.20.2.2  jdolecek 		} else {
    150  1.20.2.2  jdolecek 			continue;
    151  1.20.2.2  jdolecek 		}
    152  1.20.2.2  jdolecek 		mm_mprotect(bootspace.segs[i].va, bootspace.segs[i].sz, prot);
    153  1.20.2.2  jdolecek 	}
    154  1.20.2.2  jdolecek 
    155  1.20.2.2  jdolecek 	print_state(true, "Segments protection updated");
    156  1.20.2.2  jdolecek }
    157  1.20.2.2  jdolecek 
    158  1.20.2.2  jdolecek static size_t
    159  1.20.2.2  jdolecek mm_nentries_range(vaddr_t startva, vaddr_t endva, size_t pgsz)
    160  1.20.2.2  jdolecek {
    161  1.20.2.2  jdolecek 	size_t npages;
    162  1.20.2.2  jdolecek 
    163  1.20.2.2  jdolecek 	npages = roundup((endva / PAGE_SIZE), (pgsz / PAGE_SIZE)) -
    164  1.20.2.2  jdolecek 	    rounddown((startva / PAGE_SIZE), (pgsz / PAGE_SIZE));
    165  1.20.2.2  jdolecek 	return (npages / (pgsz / PAGE_SIZE));
    166  1.20.2.2  jdolecek }
    167  1.20.2.2  jdolecek 
    168  1.20.2.2  jdolecek static void
    169  1.20.2.2  jdolecek mm_map_tree(vaddr_t startva, vaddr_t endva)
    170  1.20.2.2  jdolecek {
    171  1.20.2.2  jdolecek 	size_t i, nL4e, nL3e, nL2e;
    172  1.20.2.2  jdolecek 	size_t L4e_idx, L3e_idx, L2e_idx;
    173  1.20.2.2  jdolecek 	paddr_t pa;
    174  1.20.2.2  jdolecek 
    175  1.20.2.2  jdolecek 	/* Build L4. */
    176  1.20.2.2  jdolecek 	L4e_idx = pl4_i(startva);
    177  1.20.2.2  jdolecek 	nL4e = mm_nentries_range(startva, endva, NBPD_L4);
    178  1.20.2.2  jdolecek 	ASSERT(L4e_idx == 511);
    179  1.20.2.2  jdolecek 	ASSERT(nL4e == 1);
    180  1.20.2.2  jdolecek 	if (!mm_pte_is_valid(L4_BASE[L4e_idx])) {
    181  1.20.2.2  jdolecek 		pa = mm_palloc(1);
    182  1.20.2.2  jdolecek 		L4_BASE[L4e_idx] = pa | PG_V | PG_RW;
    183  1.20.2.2  jdolecek 	}
    184  1.20.2.2  jdolecek 
    185  1.20.2.2  jdolecek 	/* Build L3. */
    186  1.20.2.2  jdolecek 	L3e_idx = pl3_i(startva);
    187  1.20.2.2  jdolecek 	nL3e = mm_nentries_range(startva, endva, NBPD_L3);
    188  1.20.2.2  jdolecek 	for (i = 0; i < nL3e; i++) {
    189  1.20.2.2  jdolecek 		if (mm_pte_is_valid(L3_BASE[L3e_idx+i])) {
    190  1.20.2.2  jdolecek 			continue;
    191  1.20.2.2  jdolecek 		}
    192  1.20.2.2  jdolecek 		pa = mm_palloc(1);
    193  1.20.2.2  jdolecek 		L3_BASE[L3e_idx+i] = pa | PG_V | PG_RW;
    194  1.20.2.2  jdolecek 	}
    195  1.20.2.2  jdolecek 
    196  1.20.2.2  jdolecek 	/* Build L2. */
    197  1.20.2.2  jdolecek 	L2e_idx = pl2_i(startva);
    198  1.20.2.2  jdolecek 	nL2e = mm_nentries_range(startva, endva, NBPD_L2);
    199  1.20.2.2  jdolecek 	for (i = 0; i < nL2e; i++) {
    200  1.20.2.2  jdolecek 		if (mm_pte_is_valid(L2_BASE[L2e_idx+i])) {
    201  1.20.2.2  jdolecek 			continue;
    202  1.20.2.2  jdolecek 		}
    203  1.20.2.2  jdolecek 		pa = mm_palloc(1);
    204  1.20.2.2  jdolecek 		L2_BASE[L2e_idx+i] = pa | PG_V | PG_RW;
    205  1.20.2.2  jdolecek 	}
    206  1.20.2.2  jdolecek }
    207  1.20.2.2  jdolecek 
    208  1.20.2.2  jdolecek static vaddr_t
    209  1.20.2.2  jdolecek mm_randva_kregion(size_t size, size_t pagesz)
    210  1.20.2.2  jdolecek {
    211  1.20.2.2  jdolecek 	vaddr_t sva, eva;
    212  1.20.2.2  jdolecek 	vaddr_t randva;
    213  1.20.2.2  jdolecek 	uint64_t rnd;
    214  1.20.2.2  jdolecek 	size_t i;
    215  1.20.2.2  jdolecek 	bool ok;
    216  1.20.2.2  jdolecek 
    217  1.20.2.2  jdolecek 	while (1) {
    218  1.20.2.2  jdolecek 		prng_get_rand(&rnd, sizeof(rnd));
    219  1.20.2.2  jdolecek 		randva = rounddown(KASLR_WINDOW_BASE +
    220  1.20.2.2  jdolecek 		    rnd % (KASLR_WINDOW_SIZE - size), pagesz);
    221  1.20.2.2  jdolecek 
    222  1.20.2.2  jdolecek 		/* Detect collisions */
    223  1.20.2.2  jdolecek 		ok = true;
    224  1.20.2.2  jdolecek 		for (i = 0; i < BTSPACE_NSEGS; i++) {
    225  1.20.2.2  jdolecek 			if (bootspace.segs[i].type == BTSEG_NONE) {
    226  1.20.2.2  jdolecek 				continue;
    227  1.20.2.2  jdolecek 			}
    228  1.20.2.2  jdolecek 			sva = bootspace.segs[i].va;
    229  1.20.2.2  jdolecek 			eva = sva + bootspace.segs[i].sz;
    230  1.20.2.2  jdolecek 
    231  1.20.2.2  jdolecek 			if ((sva <= randva) && (randva < eva)) {
    232  1.20.2.2  jdolecek 				ok = false;
    233  1.20.2.2  jdolecek 				break;
    234  1.20.2.2  jdolecek 			}
    235  1.20.2.2  jdolecek 			if ((sva < randva + size) && (randva + size <= eva)) {
    236  1.20.2.2  jdolecek 				ok = false;
    237  1.20.2.2  jdolecek 				break;
    238  1.20.2.2  jdolecek 			}
    239  1.20.2.2  jdolecek 			if (randva < sva && eva < (randva + size)) {
    240  1.20.2.2  jdolecek 				ok = false;
    241  1.20.2.2  jdolecek 				break;
    242  1.20.2.2  jdolecek 			}
    243  1.20.2.2  jdolecek 		}
    244  1.20.2.2  jdolecek 		if (ok) {
    245  1.20.2.2  jdolecek 			break;
    246  1.20.2.2  jdolecek 		}
    247  1.20.2.2  jdolecek 	}
    248  1.20.2.2  jdolecek 
    249  1.20.2.2  jdolecek 	mm_map_tree(randva, randva + size);
    250  1.20.2.2  jdolecek 
    251  1.20.2.2  jdolecek 	return randva;
    252  1.20.2.2  jdolecek }
    253  1.20.2.2  jdolecek 
    254  1.20.2.2  jdolecek static paddr_t
    255  1.20.2.2  jdolecek bootspace_getend(void)
    256  1.20.2.2  jdolecek {
    257  1.20.2.2  jdolecek 	paddr_t pa, max = 0;
    258  1.20.2.2  jdolecek 	size_t i;
    259  1.20.2.2  jdolecek 
    260  1.20.2.2  jdolecek 	for (i = 0; i < BTSPACE_NSEGS; i++) {
    261  1.20.2.2  jdolecek 		if (bootspace.segs[i].type == BTSEG_NONE) {
    262  1.20.2.2  jdolecek 			continue;
    263  1.20.2.2  jdolecek 		}
    264  1.20.2.2  jdolecek 		pa = bootspace.segs[i].pa + bootspace.segs[i].sz;
    265  1.20.2.2  jdolecek 		if (pa > max)
    266  1.20.2.2  jdolecek 			max = pa;
    267  1.20.2.2  jdolecek 	}
    268  1.20.2.2  jdolecek 
    269  1.20.2.2  jdolecek 	return max;
    270  1.20.2.2  jdolecek }
    271  1.20.2.2  jdolecek 
    272  1.20.2.2  jdolecek static void
    273  1.20.2.2  jdolecek bootspace_addseg(int type, vaddr_t va, paddr_t pa, size_t sz)
    274  1.20.2.2  jdolecek {
    275  1.20.2.2  jdolecek 	size_t i;
    276  1.20.2.2  jdolecek 
    277  1.20.2.2  jdolecek 	for (i = 0; i < BTSPACE_NSEGS; i++) {
    278  1.20.2.2  jdolecek 		if (bootspace.segs[i].type == BTSEG_NONE) {
    279  1.20.2.2  jdolecek 			bootspace.segs[i].type = type;
    280  1.20.2.2  jdolecek 			bootspace.segs[i].va = va;
    281  1.20.2.2  jdolecek 			bootspace.segs[i].pa = pa;
    282  1.20.2.2  jdolecek 			bootspace.segs[i].sz = sz;
    283  1.20.2.2  jdolecek 			return;
    284  1.20.2.2  jdolecek 		}
    285  1.20.2.2  jdolecek 	}
    286  1.20.2.2  jdolecek 
    287  1.20.2.2  jdolecek 	fatal("bootspace_addseg: segments full");
    288  1.20.2.2  jdolecek }
    289  1.20.2.2  jdolecek 
    290  1.20.2.2  jdolecek static size_t
    291  1.20.2.2  jdolecek mm_shift_segment(vaddr_t va, size_t pagesz, size_t elfsz, size_t elfalign)
    292  1.20.2.2  jdolecek {
    293  1.20.2.2  jdolecek 	size_t shiftsize, offset;
    294  1.20.2.2  jdolecek 	uint64_t rnd;
    295  1.20.2.2  jdolecek 
    296  1.20.2.2  jdolecek 	if (elfalign == 0) {
    297  1.20.2.2  jdolecek 		elfalign = ELFROUND;
    298  1.20.2.2  jdolecek 	}
    299  1.20.2.2  jdolecek 
    300  1.20.2.2  jdolecek 	ASSERT(pagesz >= elfalign);
    301  1.20.2.2  jdolecek 	ASSERT(pagesz % elfalign == 0);
    302  1.20.2.2  jdolecek 	shiftsize = roundup(elfsz, pagesz) - roundup(elfsz, elfalign);
    303  1.20.2.2  jdolecek 	if (shiftsize == 0) {
    304  1.20.2.2  jdolecek 		return 0;
    305  1.20.2.2  jdolecek 	}
    306  1.20.2.2  jdolecek 
    307  1.20.2.2  jdolecek 	prng_get_rand(&rnd, sizeof(rnd));
    308  1.20.2.2  jdolecek 	offset = roundup(rnd % shiftsize, elfalign);
    309  1.20.2.2  jdolecek 	ASSERT((va + offset) % elfalign == 0);
    310  1.20.2.2  jdolecek 
    311  1.20.2.2  jdolecek 	memmove((void *)(va + offset), (void *)va, elfsz);
    312  1.20.2.2  jdolecek 
    313  1.20.2.2  jdolecek 	return offset;
    314  1.20.2.2  jdolecek }
    315  1.20.2.2  jdolecek 
    316  1.20.2.2  jdolecek static void
    317  1.20.2.2  jdolecek mm_map_head(void)
    318  1.20.2.2  jdolecek {
    319  1.20.2.2  jdolecek 	size_t i, npages, size;
    320  1.20.2.2  jdolecek 	uint64_t rnd;
    321  1.20.2.2  jdolecek 	vaddr_t randva;
    322  1.20.2.2  jdolecek 
    323  1.20.2.2  jdolecek 	/*
    324  1.20.2.2  jdolecek 	 * To get the size of the head, we give a look at the read-only
    325  1.20.2.2  jdolecek 	 * mapping of the kernel we created in locore. We're identity mapped,
    326  1.20.2.2  jdolecek 	 * so kernpa = kernva.
    327  1.20.2.2  jdolecek 	 */
    328  1.20.2.2  jdolecek 	size = elf_get_head_size((vaddr_t)kernpa_start);
    329  1.20.2.2  jdolecek 	npages = size / PAGE_SIZE;
    330  1.20.2.2  jdolecek 
    331  1.20.2.2  jdolecek 	prng_get_rand(&rnd, sizeof(rnd));
    332  1.20.2.2  jdolecek 	randva = rounddown(HEAD_WINDOW_BASE + rnd % (HEAD_WINDOW_SIZE - size),
    333  1.20.2.2  jdolecek 	    PAGE_SIZE);
    334  1.20.2.2  jdolecek 	mm_map_tree(randva, randva + size);
    335  1.20.2.2  jdolecek 
    336  1.20.2.2  jdolecek 	/* Enter the area and build the ELF info */
    337  1.20.2.2  jdolecek 	for (i = 0; i < npages; i++) {
    338  1.20.2.2  jdolecek 		mm_enter_pa(kernpa_start + i * PAGE_SIZE,
    339  1.20.2.2  jdolecek 		    randva + i * PAGE_SIZE, MM_PROT_READ|MM_PROT_WRITE);
    340  1.20.2.2  jdolecek 	}
    341  1.20.2.2  jdolecek 	elf_build_head(randva);
    342  1.20.2.2  jdolecek 
    343  1.20.2.2  jdolecek 	/* Register the values in bootspace */
    344  1.20.2.2  jdolecek 	bootspace.head.va = randva;
    345  1.20.2.2  jdolecek 	bootspace.head.pa = kernpa_start;
    346  1.20.2.2  jdolecek 	bootspace.head.sz = size;
    347  1.20.2.2  jdolecek }
    348  1.20.2.2  jdolecek 
    349  1.20.2.2  jdolecek vaddr_t
    350  1.20.2.2  jdolecek mm_map_segment(int segtype, paddr_t pa, size_t elfsz, size_t elfalign)
    351  1.20.2.2  jdolecek {
    352  1.20.2.2  jdolecek 	size_t i, npages, size, pagesz, offset;
    353  1.20.2.2  jdolecek 	vaddr_t randva;
    354  1.20.2.2  jdolecek 	char pad;
    355  1.20.2.2  jdolecek 
    356  1.20.2.2  jdolecek 	if (elfsz <= PAGE_SIZE) {
    357  1.20.2.2  jdolecek 		pagesz = NBPD_L1;
    358  1.20.2.2  jdolecek 	} else {
    359  1.20.2.2  jdolecek 		pagesz = NBPD_L2;
    360  1.20.2.2  jdolecek 	}
    361  1.20.2.2  jdolecek 
    362  1.20.2.2  jdolecek 	size = roundup(elfsz, pagesz);
    363  1.20.2.2  jdolecek 	randva = mm_randva_kregion(size, pagesz);
    364  1.20.2.2  jdolecek 
    365  1.20.2.2  jdolecek 	npages = size / PAGE_SIZE;
    366  1.20.2.2  jdolecek 	for (i = 0; i < npages; i++) {
    367  1.20.2.2  jdolecek 		mm_enter_pa(pa + i * PAGE_SIZE,
    368  1.20.2.2  jdolecek 		    randva + i * PAGE_SIZE, MM_PROT_READ|MM_PROT_WRITE);
    369  1.20.2.2  jdolecek 	}
    370  1.20.2.2  jdolecek 
    371  1.20.2.2  jdolecek 	offset = mm_shift_segment(randva, pagesz, elfsz, elfalign);
    372  1.20.2.2  jdolecek 	ASSERT(offset + elfsz <= size);
    373  1.20.2.2  jdolecek 
    374  1.20.2.2  jdolecek 	pad = pads[segtype];
    375  1.20.2.2  jdolecek 	memset((void *)randva, pad, offset);
    376  1.20.2.2  jdolecek 	memset((void *)(randva + offset + elfsz), pad, size - elfsz - offset);
    377  1.20.2.2  jdolecek 
    378  1.20.2.2  jdolecek 	bootspace_addseg(segtype, randva, pa, size);
    379  1.20.2.2  jdolecek 
    380  1.20.2.2  jdolecek 	return (randva + offset);
    381  1.20.2.2  jdolecek }
    382  1.20.2.2  jdolecek 
    383  1.20.2.2  jdolecek static void
    384  1.20.2.2  jdolecek mm_map_boot(void)
    385  1.20.2.2  jdolecek {
    386  1.20.2.2  jdolecek 	size_t i, npages, size;
    387  1.20.2.2  jdolecek 	vaddr_t randva;
    388  1.20.2.2  jdolecek 	paddr_t bootpa;
    389  1.20.2.2  jdolecek 
    390  1.20.2.2  jdolecek 	/*
    391  1.20.2.2  jdolecek 	 * The "boot" region is special: its page tree has a fixed size, but
    392  1.20.2.2  jdolecek 	 * the number of pages entered is lower.
    393  1.20.2.2  jdolecek 	 */
    394  1.20.2.2  jdolecek 
    395  1.20.2.2  jdolecek 	/* Create the page tree */
    396  1.20.2.2  jdolecek 	size = (NKL2_KIMG_ENTRIES + 1) * NBPD_L2;
    397  1.20.2.2  jdolecek 	randva = mm_randva_kregion(size, PAGE_SIZE);
    398  1.20.2.2  jdolecek 
    399  1.20.2.2  jdolecek 	/* Enter the area and build the ELF info */
    400  1.20.2.2  jdolecek 	bootpa = bootspace_getend();
    401  1.20.2.2  jdolecek 	size = (pa_avail - bootpa);
    402  1.20.2.2  jdolecek 	npages = size / PAGE_SIZE;
    403  1.20.2.2  jdolecek 	for (i = 0; i < npages; i++) {
    404  1.20.2.2  jdolecek 		mm_enter_pa(bootpa + i * PAGE_SIZE,
    405  1.20.2.2  jdolecek 		    randva + i * PAGE_SIZE, MM_PROT_READ|MM_PROT_WRITE);
    406  1.20.2.2  jdolecek 	}
    407  1.20.2.2  jdolecek 	elf_build_boot(randva, bootpa);
    408  1.20.2.2  jdolecek 
    409  1.20.2.2  jdolecek 	/* Enter the ISA I/O MEM */
    410  1.20.2.2  jdolecek 	iom_base = randva + npages * PAGE_SIZE;
    411  1.20.2.2  jdolecek 	npages = IOM_SIZE / PAGE_SIZE;
    412  1.20.2.2  jdolecek 	for (i = 0; i < npages; i++) {
    413  1.20.2.2  jdolecek 		mm_enter_pa(IOM_BEGIN + i * PAGE_SIZE,
    414  1.20.2.2  jdolecek 		    iom_base + i * PAGE_SIZE, MM_PROT_READ|MM_PROT_WRITE);
    415  1.20.2.2  jdolecek 	}
    416  1.20.2.2  jdolecek 
    417  1.20.2.2  jdolecek 	/* Register the values in bootspace */
    418  1.20.2.2  jdolecek 	bootspace.boot.va = randva;
    419  1.20.2.2  jdolecek 	bootspace.boot.pa = bootpa;
    420  1.20.2.2  jdolecek 	bootspace.boot.sz = (size_t)(iom_base + IOM_SIZE) -
    421  1.20.2.2  jdolecek 	    (size_t)bootspace.boot.va;
    422  1.20.2.2  jdolecek 
    423  1.20.2.2  jdolecek 	/* Initialize the values that are located in the "boot" region */
    424  1.20.2.2  jdolecek 	extern uint64_t PDPpaddr;
    425  1.20.2.2  jdolecek 	bootspace.spareva = bootspace.boot.va + NKL2_KIMG_ENTRIES * NBPD_L2;
    426  1.20.2.2  jdolecek 	bootspace.pdir = bootspace.boot.va + (PDPpaddr - bootspace.boot.pa);
    427  1.20.2.2  jdolecek 	bootspace.emodule = bootspace.boot.va + NKL2_KIMG_ENTRIES * NBPD_L2;
    428  1.20.2.2  jdolecek }
    429  1.20.2.2  jdolecek 
    430  1.20.2.2  jdolecek /*
    431  1.20.2.2  jdolecek  * There is a variable number of independent regions: one head, several kernel
    432  1.20.2.2  jdolecek  * segments, one boot. They are all mapped at random VAs.
    433  1.20.2.2  jdolecek  *
    434  1.20.2.2  jdolecek  * Head contains the ELF Header and ELF Section Headers, and we use them to
    435  1.20.2.2  jdolecek  * map the rest of the regions. Head must be placed in memory *before* the
    436  1.20.2.2  jdolecek  * other regions.
    437  1.20.2.2  jdolecek  *
    438  1.20.2.2  jdolecek  * At the end of this function, the bootspace structure is fully constructed.
    439  1.20.2.2  jdolecek  */
    440  1.20.2.2  jdolecek void
    441  1.20.2.2  jdolecek mm_map_kernel(void)
    442  1.20.2.2  jdolecek {
    443  1.20.2.2  jdolecek 	memset(&bootspace, 0, sizeof(bootspace));
    444  1.20.2.2  jdolecek 	mm_map_head();
    445  1.20.2.2  jdolecek 	print_state(true, "Head region mapped");
    446  1.20.2.2  jdolecek 	elf_map_sections();
    447  1.20.2.2  jdolecek 	print_state(true, "Segments mapped");
    448  1.20.2.2  jdolecek 	mm_map_boot();
    449  1.20.2.2  jdolecek 	print_state(true, "Boot region mapped");
    450  1.20.2.2  jdolecek }
    451