diff options
| author | Marcel Moolenaar <marcel@FreeBSD.org> | 2011-03-13 22:04:19 +0000 |
|---|---|---|
| committer | Marcel Moolenaar <marcel@FreeBSD.org> | 2011-03-13 22:04:19 +0000 |
| commit | 72e168018936130e7b848a95a2b19d9c09cee250 (patch) | |
| tree | 9325df38a7549cc65c5d216a84fd9b99f6fe635d /sys/boot | |
| parent | 7bd6af277deb67a802884e58c52840e3885d87a3 (diff) | |
Notes
Diffstat (limited to 'sys/boot')
| -rw-r--r-- | sys/boot/ia64/common/copy.c | 10 | ||||
| -rw-r--r-- | sys/boot/ia64/common/exec.c | 98 |
2 files changed, 68 insertions, 40 deletions
diff --git a/sys/boot/ia64/common/copy.c b/sys/boot/ia64/common/copy.c index 4f4913b4631d..93ef77b26681 100644 --- a/sys/boot/ia64/common/copy.c +++ b/sys/boot/ia64/common/copy.c @@ -43,6 +43,8 @@ pgtbl_extend(u_int idx) u_int pot; pgtblsz = (idx + 1) << 3; + + /* The minimum size is 4KB. */ if (pgtblsz < 4096) pgtblsz = 4096; @@ -52,6 +54,14 @@ pgtbl_extend(u_int idx) pgtblsz = pgtblsz | (pgtblsz >> pot); pgtblsz++; + /* The maximum size is 1MB. */ + if (pgtblsz > 1048576) + return (ENOMEM); + + /* Make sure the size is a valid (mappable) page size. */ + if (pgtblsz == 32*1024 || pgtblsz == 128*1024 || pgtblsz == 512*1024) + pgtblsz <<= 1; + /* Allocate naturally aligned memory. */ pgtbl = (void *)ia64_platform_alloc(0, pgtblsz); if (pgtbl == NULL) diff --git a/sys/boot/ia64/common/exec.c b/sys/boot/ia64/common/exec.c index dc7cdafbd206..ab35bd7b6ce1 100644 --- a/sys/boot/ia64/common/exec.c +++ b/sys/boot/ia64/common/exec.c @@ -85,9 +85,52 @@ enter_kernel(uint64_t start, struct bootinfo *bi) } static void -mmu_setup_legacy(uint64_t entry) +mmu_wire(vm_offset_t va, vm_paddr_t pa, u_int sz, u_int acc) { + static u_int iidx = 0, didx = 0; pt_entry_t pte; + u_int shft; + + /* Round up to the smallest possible page size. */ + if (sz < 4096) + sz = 4096; + /* Determine the exponent (base 2). */ + shft = 0; + while (sz > 1) { + shft++; + sz >>= 1; + } + /* Truncate to the largest possible page size (256MB). */ + if (shft > 28) + shft = 28; + /* Round down to a valid (mappable) page size. */ + if (shft > 14 && (shft & 1) != 0) + shft--; + + pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY | + PTE_PL_KERN | (acc & PTE_AR_MASK) | (pa & PTE_PPN_MASK); + + __asm __volatile("mov cr.ifa=%0" :: "r"(va)); + __asm __volatile("mov cr.itir=%0" :: "r"(shft << 2)); + __asm __volatile("srlz.d;;"); + __asm __volatile("ptr.d %0,%1" :: "r"(va), "r"(shft << 2)); + __asm __volatile("srlz.d;;"); + __asm __volatile("itr.d dtr[%0]=%1" :: "r"(didx), "r"(pte)); + __asm __volatile("srlz.d;;"); + didx++; + + if (acc == PTE_AR_RWX) { + __asm __volatile("ptr.i %0,%1;;" :: "r"(va), "r"(shft << 2)); + __asm __volatile("srlz.i;;"); + __asm __volatile("itr.i itr[%0]=%1;;" :: "r"(iidx), "r"(pte)); + __asm __volatile("srlz.i;;"); + iidx++; + } +} + +static void +mmu_setup_legacy(uint64_t entry) +{ /* * Region 6 is direct mapped UC and region 7 is direct mapped @@ -99,53 +142,28 @@ mmu_setup_legacy(uint64_t entry) ia64_set_rr(IA64_RR_BASE(7), (7 << 8) | (28 << 2)); __asm __volatile("srlz.i;;"); - pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY | - PTE_PL_KERN | PTE_AR_RWX | PTE_ED; - pte |= IA64_RR_MASK(entry) & PTE_PPN_MASK; - - __asm __volatile("mov cr.ifa=%0" :: "r"(entry)); - __asm __volatile("mov cr.itir=%0" :: "r"(28 << 2)); - __asm __volatile("ptr.i %0,%1" :: "r"(entry), "r"(28<<2)); - __asm __volatile("ptr.d %0,%1" :: "r"(entry), "r"(28<<2)); - __asm __volatile("srlz.i;;"); - __asm __volatile("itr.i itr[%0]=%1;;" :: "r"(0), "r"(pte)); - __asm __volatile("srlz.i;;"); - __asm __volatile("itr.d dtr[%0]=%1;;" :: "r"(0), "r"(pte)); - __asm __volatile("srlz.i;;"); + mmu_wire(entry, IA64_RR_MASK(entry), 1UL << 28, PTE_AR_RWX); } static void -mmu_setup_paged(void) +mmu_setup_paged(vm_offset_t pbvm_top) { - pt_entry_t pte; u_int sz; - ia64_set_rr(IA64_RR_BASE(4), (4 << 8) | (IA64_PBVM_PAGE_SHIFT << 2)); + ia64_set_rr(IA64_RR_BASE(IA64_PBVM_RR), + (IA64_PBVM_RR << 8) | (IA64_PBVM_PAGE_SHIFT << 2)); __asm __volatile("srlz.i;;"); - /* - * Wire the PBVM page table. - */ - - pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY | - PTE_PL_KERN | PTE_AR_RWX | PTE_ED; - pte |= ia64_pgtbl[0] & PTE_PPN_MASK; + /* Wire the PBVM page table. */ + mmu_wire(IA64_PBVM_PGTBL, (uintptr_t)ia64_pgtbl, ia64_pgtblsz, + PTE_AR_RW); - /* - * Size of the translation. This should be the largest power of 2 - * smaller than the LVM in use. - */ - sz = 24; - - __asm __volatile("mov cr.ifa=%0" :: "r"(IA64_PBVM_BASE)); - __asm __volatile("mov cr.itir=%0" :: "r"(sz << 2)); - __asm __volatile("ptr.i %0,%1" :: "r"(IA64_PBVM_BASE), "r"(sz << 2)); - __asm __volatile("ptr.d %0,%1" :: "r"(IA64_PBVM_BASE), "r"(sz << 2)); - __asm __volatile("srlz.i;;"); - __asm __volatile("itr.i itr[%0]=%1;;" :: "r"(0), "r"(pte)); - __asm __volatile("srlz.i;;"); - __asm __volatile("itr.d dtr[%0]=%1;;" :: "r"(0), "r"(pte)); - __asm __volatile("srlz.i;;"); + /* Wire as much of the PBVM we can. This must be a power of 2. */ + pbvm_top = (pbvm_top + IA64_PBVM_PAGE_MASK) & ~IA64_PBVM_PAGE_MASK; + sz = pbvm_top - IA64_PBVM_BASE; + while (sz & (sz - 1)) + sz -= IA64_PBVM_PAGE_SIZE; + mmu_wire(IA64_PBVM_BASE, ia64_pgtbl[0], sz, PTE_AR_RWX); } static int @@ -177,7 +195,7 @@ elf64_exec(struct preloaded_file *fp) if (IS_LEGACY_KERNEL()) mmu_setup_legacy(hdr->e_entry); else - mmu_setup_paged(); + mmu_setup_paged((uintptr_t)(bi + 1)); enter_kernel(hdr->e_entry, bi); /* NOTREACHED */ |
