aboutsummaryrefslogtreecommitdiff
path: root/sys/boot
diff options
context:
space:
mode:
authorMarcel Moolenaar <marcel@FreeBSD.org>2011-03-13 22:04:19 +0000
committerMarcel Moolenaar <marcel@FreeBSD.org>2011-03-13 22:04:19 +0000
commit72e168018936130e7b848a95a2b19d9c09cee250 (patch)
tree9325df38a7549cc65c5d216a84fd9b99f6fe635d /sys/boot
parent7bd6af277deb67a802884e58c52840e3885d87a3 (diff)
Notes
Diffstat (limited to 'sys/boot')
-rw-r--r--sys/boot/ia64/common/copy.c10
-rw-r--r--sys/boot/ia64/common/exec.c98
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 */