summaryrefslogtreecommitdiffstats
path: root/sys/boot/ia64/common/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/boot/ia64/common/exec.c')
-rw-r--r--sys/boot/ia64/common/exec.c164
1 files changed, 126 insertions, 38 deletions
diff --git a/sys/boot/ia64/common/exec.c b/sys/boot/ia64/common/exec.c
index 1a8094f..cb91141 100644
--- a/sys/boot/ia64/common/exec.c
+++ b/sys/boot/ia64/common/exec.c
@@ -36,25 +36,36 @@ __FBSDID("$FreeBSD$");
#include <machine/ia64_cpu.h>
#include <machine/pte.h>
-#include <ia64/include/bootinfo.h>
#include <ia64/include/vmparam.h>
#include <efi.h>
#include <efilib.h>
-#include "bootstrap.h"
+#include "libia64.h"
-#define _KERNEL
+static int elf64_exec(struct preloaded_file *amp);
+static int elf64_obj_exec(struct preloaded_file *amp);
-static int elf64_exec(struct preloaded_file *amp);
+static struct file_format ia64_elf = {
+ elf64_loadfile,
+ elf64_exec
+};
+static struct file_format ia64_elf_obj = {
+ elf64_obj_loadfile,
+ elf64_obj_exec
+};
-struct file_format ia64_elf = { elf64_loadfile, elf64_exec };
+struct file_format *file_formats[] = {
+ &ia64_elf,
+ &ia64_elf_obj,
+ NULL
+};
/*
* Entered with psr.ic and psr.i both zero.
*/
-void
-enter_kernel(uint64_t start, uint64_t bi)
+static void
+enter_kernel(uint64_t start, struct bootinfo *bi)
{
__asm __volatile("srlz.i;;");
@@ -73,53 +84,130 @@ enter_kernel(uint64_t start, uint64_t bi)
/* NOTREACHED */
}
-static int
-elf64_exec(struct preloaded_file *fp)
+static void
+mmu_wire(vm_offset_t va, vm_paddr_t pa, vm_size_t sz, u_int acc)
{
- struct file_metadata *md;
- Elf_Ehdr *hdr;
- pt_entry_t pte;
- uint64_t bi_addr;
+ 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--;
- md = file_findmetadata(fp, MODINFOMD_ELFHDR);
- if (md == NULL)
- return (EINVAL);
- hdr = (Elf_Ehdr *)&(md->md_data);
-
- bi_load(fp, &bi_addr);
-
- printf("Entering %s at 0x%lx...\n", fp->f_name, hdr->e_entry);
-
- ldr_enter(fp->f_name);
+ 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++;
+ }
+}
- __asm __volatile("rsm psr.ic|psr.i;;");
- __asm __volatile("srlz.i;;");
+static void
+mmu_setup_legacy(uint64_t entry)
+{
/*
* Region 6 is direct mapped UC and region 7 is direct mapped
* WC. The details of this is controlled by the Alt {I,D}TLB
- * handlers. Here we just make sure that they have the largest
+ * handlers. Here we just make sure that they have the largest
* possible page size to minimise TLB usage.
*/
ia64_set_rr(IA64_RR_BASE(6), (6 << 8) | (28 << 2));
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(hdr->e_entry) & PTE_PPN_MASK;
+ mmu_wire(entry, IA64_RR_MASK(entry), 1UL << 28, PTE_AR_RWX);
+}
- __asm __volatile("mov cr.ifa=%0" :: "r"(hdr->e_entry));
- __asm __volatile("mov cr.itir=%0" :: "r"(28 << 2));
- __asm __volatile("ptr.i %0,%1" :: "r"(hdr->e_entry), "r"(28<<2));
- __asm __volatile("ptr.d %0,%1" :: "r"(hdr->e_entry), "r"(28<<2));
- __asm __volatile("srlz.i;;");
- __asm __volatile("itr.i itr[%0]=%1;;" :: "r"(0), "r"(pte));
+static void
+mmu_setup_paged(vm_offset_t pbvm_top)
+{
+ vm_size_t sz;
+
+ ia64_set_rr(IA64_RR_BASE(IA64_PBVM_RR),
+ (IA64_PBVM_RR << 8) | (IA64_PBVM_PAGE_SHIFT << 2));
__asm __volatile("srlz.i;;");
- __asm __volatile("itr.d dtr[%0]=%1;;" :: "r"(0), "r"(pte));
+
+ /* Wire the PBVM page table. */
+ mmu_wire(IA64_PBVM_PGTBL, (uintptr_t)ia64_pgtbl, ia64_pgtblsz,
+ PTE_AR_RW);
+
+ /* Wire as much of the PBVM we can. This must be a power of 2. */
+ sz = pbvm_top - IA64_PBVM_BASE;
+ sz = (sz + IA64_PBVM_PAGE_MASK) & ~IA64_PBVM_PAGE_MASK;
+ while (sz & (sz - 1))
+ sz -= IA64_PBVM_PAGE_SIZE;
+ mmu_wire(IA64_PBVM_BASE, ia64_pgtbl[0], sz, PTE_AR_RWX);
+}
+
+static int
+elf64_exec(struct preloaded_file *fp)
+{
+ struct bootinfo *bi;
+ struct file_metadata *md;
+ Elf_Ehdr *hdr;
+ int error;
+
+ md = file_findmetadata(fp, MODINFOMD_ELFHDR);
+ if (md == NULL)
+ return (EINVAL);
+
+ error = ia64_bootinfo(fp, &bi);
+ if (error)
+ return (error);
+
+ hdr = (Elf_Ehdr *)&(md->md_data);
+ printf("Entering %s at 0x%lx...\n", fp->f_name, hdr->e_entry);
+
+ error = ia64_platform_enter(fp->f_name);
+ if (error)
+ return (error);
+
+ __asm __volatile("rsm psr.ic|psr.i;;");
__asm __volatile("srlz.i;;");
- enter_kernel(hdr->e_entry, bi_addr);
+ if (IS_LEGACY_KERNEL())
+ mmu_setup_legacy(hdr->e_entry);
+ else
+ mmu_setup_paged((uintptr_t)(bi + 1));
+ enter_kernel(hdr->e_entry, bi);
/* NOTREACHED */
- return (0);
+ return (EDOOFUS);
+}
+
+static int
+elf64_obj_exec(struct preloaded_file *fp)
+{
+
+ printf("%s called for preloaded file %p (=%s):\n", __func__, fp,
+ fp->f_name);
+ return (ENOSYS);
}
OpenPOWER on IntegriCloud