summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/boot/common/Makefile.inc4
-rw-r--r--sys/boot/efi/libefi/libefi.c2
-rw-r--r--sys/boot/ia64/common/bootinfo.c28
-rw-r--r--sys/boot/ia64/common/copy.c83
-rw-r--r--sys/boot/ia64/common/exec.c164
-rw-r--r--sys/boot/ia64/common/libia64.h27
-rw-r--r--sys/boot/ia64/efi/conf.c11
-rw-r--r--sys/boot/ia64/efi/efimd.c188
-rw-r--r--sys/boot/ia64/efi/version1
-rw-r--r--sys/boot/ia64/ski/conf.c12
-rw-r--r--sys/boot/ia64/ski/libski.h1
-rw-r--r--sys/boot/ia64/ski/skimd.c32
-rw-r--r--sys/boot/ia64/ski/version1
-rw-r--r--sys/ia64/include/bootinfo.h5
-rw-r--r--sys/ia64/include/vmparam.h46
15 files changed, 462 insertions, 143 deletions
diff --git a/sys/boot/common/Makefile.inc b/sys/boot/common/Makefile.inc
index 925e961..9893278 100644
--- a/sys/boot/common/Makefile.inc
+++ b/sys/boot/common/Makefile.inc
@@ -7,6 +7,8 @@ SRCS+= module.c panic.c
.if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64"
SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c
SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c
+.elif ${MACHINE_CPUARCH} == "ia64"
+SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c
.elif ${MACHINE} == "pc98"
SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c
.elif ${MACHINE_CPUARCH} == "arm"
@@ -14,7 +16,7 @@ SRCS+= load_elf32.c reloc_elf32.c
.elif ${MACHINE_CPUARCH} == "powerpc"
SRCS+= load_elf32.c reloc_elf32.c
SRCS+= load_elf64.c reloc_elf64.c
-.elif ${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "ia64"
+.elif ${MACHINE_CPUARCH} == "sparc64"
SRCS+= load_elf64.c reloc_elf64.c
.endif
diff --git a/sys/boot/efi/libefi/libefi.c b/sys/boot/efi/libefi/libefi.c
index 20ea48c..9e921f3 100644
--- a/sys/boot/efi/libefi/libefi.c
+++ b/sys/boot/efi/libefi/libefi.c
@@ -92,7 +92,7 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
BS = ST->BootServices;
RS = ST->RuntimeServices;
- heapsize = 512*1024;
+ heapsize = 2 * 1024 * 1024;
status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
EFI_SIZE_TO_PAGES(heapsize), &heap);
if (status != EFI_SUCCESS)
diff --git a/sys/boot/ia64/common/bootinfo.c b/sys/boot/ia64/common/bootinfo.c
index 6f892a9..076c953 100644
--- a/sys/boot/ia64/common/bootinfo.c
+++ b/sys/boot/ia64/common/bootinfo.c
@@ -226,7 +226,7 @@ bi_copymodules(vm_offset_t addr)
* - Module metadata are formatted and placed in kernel space.
*/
int
-bi_load(struct preloaded_file *fp, uint64_t *bi_addr)
+ia64_bootinfo(struct preloaded_file *fp, struct bootinfo **res)
{
struct bootinfo bi;
struct preloaded_file *xp;
@@ -234,7 +234,9 @@ bi_load(struct preloaded_file *fp, uint64_t *bi_addr)
struct devdesc *rootdev;
char *rootdevname;
vm_offset_t addr, ssym, esym;
+ int error;
+ *res = NULL;
bzero(&bi, sizeof(struct bootinfo));
bi.bi_magic = BOOTINFO_MAGIC;
bi.bi_version = 1;
@@ -289,8 +291,28 @@ bi_load(struct preloaded_file *fp, uint64_t *bi_addr)
bi.bi_envp = 0;
}
- addr = (addr + PAGE_MASK) & ~PAGE_MASK;
+ addr = (addr + 15) & ~15;
bi.bi_kernend = addr;
- return (ldr_bootinfo(&bi, bi_addr));
+ error = ia64_platform_bootinfo(&bi, res);
+ if (error)
+ return (error);
+
+ if (IS_LEGACY_KERNEL()) {
+ if (*res == NULL)
+ return (EDOOFUS);
+
+ bcopy(&bi, *res, sizeof(bi));
+ return (0);
+ }
+
+ bi.bi_pbvm_pgtbl = (uintptr_t)ia64_pgtbl;
+ bi.bi_pbvm_pgtblsz = ia64_pgtblsz;
+ ia64_copyin((void *)bi.bi_memmap, addr, bi.bi_memmap_size);
+ bi.bi_memmap = addr;
+ addr = (addr + bi.bi_memmap_size + 15) & ~15;
+ bi.bi_kernend = addr + sizeof(bi);
+ ia64_copyin(&bi, addr, sizeof(bi));
+ *res = (void *)addr;
+ return (0);
}
diff --git a/sys/boot/ia64/common/copy.c b/sys/boot/ia64/common/copy.c
index 8d8dab6..93ef77b 100644
--- a/sys/boot/ia64/common/copy.c
+++ b/sys/boot/ia64/common/copy.c
@@ -32,17 +32,98 @@ __FBSDID("$FreeBSD$");
#include "libia64.h"
+uint64_t *ia64_pgtbl;
+uint32_t ia64_pgtblsz;
+
+static int
+pgtbl_extend(u_int idx)
+{
+ uint64_t *pgtbl;
+ uint32_t pgtblsz;
+ u_int pot;
+
+ pgtblsz = (idx + 1) << 3;
+
+ /* The minimum size is 4KB. */
+ if (pgtblsz < 4096)
+ pgtblsz = 4096;
+
+ /* Find the next higher power of 2. */
+ pgtblsz--;
+ for (pot = 1; pot < 32; pot <<= 1)
+ 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)
+ return (ENOMEM);
+
+ /* Initialize new page table. */
+ if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl)
+ bcopy(ia64_pgtbl, pgtbl, ia64_pgtblsz);
+ bzero(pgtbl + (ia64_pgtblsz >> 3), pgtblsz - ia64_pgtblsz);
+
+ if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl)
+ ia64_platform_free(0, (uintptr_t)ia64_pgtbl, ia64_pgtblsz);
+
+ ia64_pgtbl = pgtbl;
+ ia64_pgtblsz = pgtblsz;
+ return (0);
+}
+
static void *
va2pa(vm_offset_t va, size_t *len)
{
uint64_t pa;
+ u_int idx, ofs;
+ int error;
+ /* Backward compatibility. */
if (va >= IA64_RR_BASE(7)) {
pa = IA64_RR_MASK(va);
return ((void *)pa);
}
- printf("\n%s: va=%lx, *len=%lx\n", __func__, va, *len);
+ if (va < IA64_PBVM_BASE) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ idx = (va - IA64_PBVM_BASE) >> IA64_PBVM_PAGE_SHIFT;
+ if (idx >= (ia64_pgtblsz >> 3)) {
+ error = pgtbl_extend(idx);
+ if (error)
+ goto fail;
+ }
+
+ ofs = va & IA64_PBVM_PAGE_MASK;
+ pa = ia64_pgtbl[idx];
+ if (pa == 0) {
+ pa = ia64_platform_alloc(va - ofs, IA64_PBVM_PAGE_SIZE);
+ if (pa == 0) {
+ error = ENOMEM;
+ goto fail;
+ }
+ ia64_pgtbl[idx] = pa;
+ }
+ pa += ofs;
+
+ /* We can not cross page boundaries (in general). */
+ if (*len + ofs > IA64_PBVM_PAGE_SIZE)
+ *len = IA64_PBVM_PAGE_SIZE - ofs;
+
+ return ((void *)pa);
+
+ fail:
*len = 0;
return (NULL);
}
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);
}
diff --git a/sys/boot/ia64/common/libia64.h b/sys/boot/ia64/common/libia64.h
index a196002..3a0119e 100644
--- a/sys/boot/ia64/common/libia64.h
+++ b/sys/boot/ia64/common/libia64.h
@@ -31,28 +31,35 @@
#include <bootstrap.h>
#include <ia64/include/bootinfo.h>
+#include <ia64/include/vmparam.h>
+
+#define IS_LEGACY_KERNEL() (ia64_pgtbl == NULL || ia64_pgtblsz == 0)
/*
* Portability functions provided by the loader
* implementation specific to the platform.
*/
-extern uint64_t ldr_alloc(vm_offset_t);
-extern int ldr_bootinfo(struct bootinfo *, uint64_t *);
-extern int ldr_enter(const char *);
+vm_paddr_t ia64_platform_alloc(vm_offset_t, vm_size_t);
+void ia64_platform_free(vm_offset_t, vm_paddr_t, vm_size_t);
+int ia64_platform_bootinfo(struct bootinfo *, struct bootinfo **);
+int ia64_platform_enter(const char *);
/*
* Functions and variables provided by the ia64 common code
* and shared by all loader implementations.
*/
+extern uint64_t *ia64_pgtbl;
+extern uint32_t ia64_pgtblsz;
-extern int ia64_autoload(void);
+int ia64_autoload(void);
+int ia64_bootinfo(struct preloaded_file *, struct bootinfo **);
-extern ssize_t ia64_copyin(const void *, vm_offset_t, size_t);
-extern ssize_t ia64_copyout(vm_offset_t, void *, size_t);
-extern ssize_t ia64_readin(int, vm_offset_t, size_t);
+ssize_t ia64_copyin(const void *, vm_offset_t, size_t);
+ssize_t ia64_copyout(vm_offset_t, void *, size_t);
+ssize_t ia64_readin(int, vm_offset_t, size_t);
-extern char *ia64_fmtdev(struct devdesc *);
-extern int ia64_getdev(void **, const char *, const char **);
-extern int ia64_setcurrdev(struct env_var *, int, const void *);
+char *ia64_fmtdev(struct devdesc *);
+int ia64_getdev(void **, const char *, const char **);
+int ia64_setcurrdev(struct env_var *, int, const void *);
#endif /* !_LIBIA64_H_ */
diff --git a/sys/boot/ia64/efi/conf.c b/sys/boot/ia64/efi/conf.c
index 69d0927..0e0d129 100644
--- a/sys/boot/ia64/efi/conf.c
+++ b/sys/boot/ia64/efi/conf.c
@@ -69,17 +69,6 @@ struct netif_driver *netif_drivers[] = {
};
/*
- * Sort formats so that those that can detect based on arguments
- * rather than reading the file go first.
- */
-extern struct file_format ia64_elf;
-
-struct file_format *file_formats[] = {
- &ia64_elf,
- NULL
-};
-
-/*
* Consoles
*
* We don't prototype these in efiboot.h because they require
diff --git a/sys/boot/ia64/efi/efimd.c b/sys/boot/ia64/efi/efimd.c
index 8a1e0c7..7454117 100644
--- a/sys/boot/ia64/efi/efimd.c
+++ b/sys/boot/ia64/efi/efimd.c
@@ -45,26 +45,147 @@ static EFI_GUID fpswa_guid = EFI_INTEL_FPSWA;
static EFI_GUID hcdp_guid = HCDP_TABLE_GUID;
+static EFI_MEMORY_DESCRIPTOR *memmap;
+static UINTN memmapsz;
static UINTN mapkey;
+static UINTN descsz;
+static UINT32 descver;
-uint64_t
-ldr_alloc(vm_offset_t va)
+#define IA64_EFI_CHUNK_SIZE (32 * 1048576)
+static vm_paddr_t ia64_efi_chunk;
+
+#define IA64_EFI_PGTBLSZ_MAX 1048576
+static vm_paddr_t ia64_efi_pgtbl;
+static vm_size_t ia64_efi_pgtblsz;
+
+/* Don't allocate memory below the boundary */
+#define IA64_EFI_ALLOC_BOUNDARY 1048576
+
+static int
+ia64_efi_memmap_update(void)
+{
+ EFI_STATUS status;
+
+ if (memmap != NULL) {
+ free(memmap);
+ memmap = NULL;
+ }
+
+ memmapsz = 0;
+ BS->GetMemoryMap(&memmapsz, NULL, &mapkey, &descsz, &descver);
+ if (memmapsz == 0)
+ return (FALSE);
+ memmap = malloc(memmapsz);
+ if (memmap == NULL)
+ return (FALSE);
+
+ status = BS->GetMemoryMap(&memmapsz, memmap, &mapkey, &descsz,
+ &descver);
+ if (EFI_ERROR(status)) {
+ free(memmap);
+ memmap = NULL;
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+static vm_paddr_t
+ia64_efi_alloc(vm_size_t sz)
{
+ EFI_PHYSICAL_ADDRESS pa;
+ EFI_MEMORY_DESCRIPTOR *mm;
+ uint8_t *mmiter, *mmiterend;
+ vm_size_t memsz;
+ UINTN npgs;
+ EFI_STATUS status;
+
+ /* We can't allocate less than a page */
+ if (sz < EFI_PAGE_SIZE)
+ return (0);
+
+ /* The size must be a power of 2. */
+ if (sz & (sz - 1))
+ return (0);
+
+ if (!ia64_efi_memmap_update())
+ return (0);
+
+ mmiter = (void *)memmap;
+ mmiterend = mmiter + memmapsz;
+ for (; mmiter < mmiterend; mmiter += descsz) {
+ mm = (void *)mmiter;
+ if (mm->Type != EfiConventionalMemory)
+ continue;
+ memsz = mm->NumberOfPages * EFI_PAGE_SIZE;
+ if (mm->PhysicalStart + memsz <= IA64_EFI_ALLOC_BOUNDARY)
+ continue;
+ /*
+ * XXX We really should make sure the memory is local to the
+ * BSP.
+ */
+ pa = (mm->PhysicalStart < IA64_EFI_ALLOC_BOUNDARY) ?
+ IA64_EFI_ALLOC_BOUNDARY : mm->PhysicalStart;
+ pa = (pa + sz - 1) & ~(sz - 1);
+ if (pa + sz > mm->PhysicalStart + memsz)
+ continue;
+
+ npgs = EFI_SIZE_TO_PAGES(sz);
+ status = BS->AllocatePages(AllocateAddress, EfiLoaderData,
+ npgs, &pa);
+ if (!EFI_ERROR(status))
+ return (pa);
+ }
+ printf("%s: unable to allocate %lx bytes\n", __func__, sz);
return (0);
}
+vm_paddr_t
+ia64_platform_alloc(vm_offset_t va, vm_size_t sz)
+{
+
+ if (va == 0) {
+ /* Page table itself. */
+ if (sz > IA64_EFI_PGTBLSZ_MAX)
+ return (0);
+ if (ia64_efi_pgtbl == 0)
+ ia64_efi_pgtbl = ia64_efi_alloc(IA64_EFI_PGTBLSZ_MAX);
+ if (ia64_efi_pgtbl != 0)
+ ia64_efi_pgtblsz = sz;
+ return (ia64_efi_pgtbl);
+ } else if (va < IA64_PBVM_BASE) {
+ /* Should not happen. */
+ return (0);
+ }
+
+ /* Loader virtual memory page. */
+ va -= IA64_PBVM_BASE;
+
+ /* Allocate a big chunk that can be wired with a single PTE. */
+ if (ia64_efi_chunk == 0)
+ ia64_efi_chunk = ia64_efi_alloc(IA64_EFI_CHUNK_SIZE);
+ if (va < IA64_EFI_CHUNK_SIZE)
+ return (ia64_efi_chunk + va);
+
+ /* Allocate a page at a time when we go beyond the chunk. */
+ return (ia64_efi_alloc(sz));
+}
+
+void
+ia64_platform_free(vm_offset_t va, vm_paddr_t pa, vm_size_t sz)
+{
+
+ BS->FreePages(pa, sz >> EFI_PAGE_SHIFT);
+}
+
int
-ldr_bootinfo(struct bootinfo *bi, uint64_t *bi_addr)
+ia64_platform_bootinfo(struct bootinfo *bi, struct bootinfo **res)
{
VOID *fpswa;
- EFI_MEMORY_DESCRIPTOR *mm;
- EFI_PHYSICAL_ADDRESS addr;
EFI_HANDLE handle;
EFI_STATUS status;
- size_t bisz;
- UINTN mmsz, pages, sz;
- UINT32 mmver;
+ UINTN sz;
bi->bi_systab = (uint64_t)ST;
bi->bi_hcdp = (uint64_t)efi_get_table(&hcdp_guid);
@@ -75,55 +196,22 @@ ldr_bootinfo(struct bootinfo *bi, uint64_t *bi_addr)
status = BS->HandleProtocol(handle, &fpswa_guid, &fpswa);
bi->bi_fpswa = (status == 0) ? (uint64_t)fpswa : 0;
- bisz = (sizeof(struct bootinfo) + 0x0f) & ~0x0f;
-
- /*
- * Allocate enough pages to hold the bootinfo block and the memory
- * map EFI will return to us. The memory map has an unknown size,
- * so we have to determine that first. Note that the AllocatePages
- * call can itself modify the memory map, so we have to take that
- * into account as well. The changes to the memory map are caused
- * by splitting a range of free memory into two (AFAICT), so that
- * one is marked as being loader data.
- */
- sz = 0;
- BS->GetMemoryMap(&sz, NULL, &mapkey, &mmsz, &mmver);
- sz += mmsz;
- sz = (sz + 15) & ~15;
- pages = EFI_SIZE_TO_PAGES(sz + bisz);
- status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages,
- &addr);
- if (EFI_ERROR(status)) {
- printf("%s: AllocatePages() returned 0x%lx\n", __func__,
- (long)status);
+ if (!ia64_efi_memmap_update())
return (ENOMEM);
- }
- /*
- * Read the memory map and stash it after bootinfo. Align the
- * memory map on a 16-byte boundary (the bootinfo block is page
- * aligned).
- */
- *bi_addr = addr;
- mm = (void *)(addr + bisz);
- sz = (EFI_PAGE_SIZE * pages) - bisz;
- status = BS->GetMemoryMap(&sz, mm, &mapkey, &mmsz, &mmver);
- if (EFI_ERROR(status)) {
- printf("%s: GetMemoryMap() returned 0x%lx\n", __func__,
- (long)status);
- return (EINVAL);
- }
- bi->bi_memmap = (uint64_t)mm;
- bi->bi_memmap_size = sz;
- bi->bi_memdesc_size = mmsz;
- bi->bi_memdesc_version = mmver;
+ bi->bi_memmap = (uint64_t)memmap;
+ bi->bi_memmap_size = memmapsz;
+ bi->bi_memdesc_size = descsz;
+ bi->bi_memdesc_version = descver;
+
+ if (IS_LEGACY_KERNEL())
+ *res = malloc(sizeof(**res));
- bcopy(bi, (void *)(*bi_addr), sizeof(*bi));
return (0);
}
int
-ldr_enter(const char *kernel)
+ia64_platform_enter(const char *kernel)
{
EFI_STATUS status;
diff --git a/sys/boot/ia64/efi/version b/sys/boot/ia64/efi/version
index a31d87d..3a947c8 100644
--- a/sys/boot/ia64/efi/version
+++ b/sys/boot/ia64/efi/version
@@ -3,6 +3,7 @@ $FreeBSD$
NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this
file is important. Make sure the current version number is on line 6.
+3.0: Add support for PBVM.
2.2: Create direct mapping based on start address instead of mapping
first 256M.
2.1: Add support for "-dev <part>" argument parsing.
diff --git a/sys/boot/ia64/ski/conf.c b/sys/boot/ia64/ski/conf.c
index cf1e163..3ee3b33 100644
--- a/sys/boot/ia64/ski/conf.c
+++ b/sys/boot/ia64/ski/conf.c
@@ -60,18 +60,6 @@ struct fs_ops *file_system[] = {
NULL
};
-/* Exported for ia64 only */
-/*
- * Sort formats so that those that can detect based on arguments
- * rather than reading the file go first.
- */
-extern struct file_format ia64_elf;
-
-struct file_format *file_formats[] = {
- &ia64_elf,
- NULL
-};
-
/*
* Consoles
*
diff --git a/sys/boot/ia64/ski/libski.h b/sys/boot/ia64/ski/libski.h
index 5bbc6de..0e7fbc6 100644
--- a/sys/boot/ia64/ski/libski.h
+++ b/sys/boot/ia64/ski/libski.h
@@ -46,7 +46,6 @@ extern int ski_boot(void);
struct bootinfo;
struct preloaded_file;
-extern int bi_load(struct bootinfo *, struct preloaded_file *);
#define SSC_CONSOLE_INIT 20
#define SSC_GETCHAR 21
diff --git a/sys/boot/ia64/ski/skimd.c b/sys/boot/ia64/ski/skimd.c
index bec2ec0..8db358c 100644
--- a/sys/boot/ia64/ski/skimd.c
+++ b/sys/boot/ia64/ski/skimd.c
@@ -33,24 +33,31 @@ __FBSDID("$FreeBSD$");
#include "libski.h"
-#define PHYS_START (4L*1024*1024*1024)
-#define PHYS_SIZE (64L*1024*1024 - 4L*1024)
-
extern void acpi_stub_init(void);
extern void efi_stub_init(struct bootinfo *);
extern void sal_stub_init(void);
-uint64_t
-ldr_alloc(vm_offset_t va)
+vm_paddr_t
+ia64_platform_alloc(vm_offset_t va, vm_size_t sz __unused)
{
+ vm_paddr_t pa;
+
+ if (va == 0)
+ pa = 1024 * 1024;
+ else
+ pa = (va - IA64_PBVM_BASE) + (64 * 1024 * 1024);
- if (va >= PHYS_SIZE)
- return (0);
- return (va + PHYS_START);
+ return (pa);
+}
+
+void
+ia64_platform_free(vm_offset_t va __unused, vm_paddr_t pa __unused,
+ vm_size_t sz __unused)
+{
}
int
-ldr_bootinfo(struct bootinfo *bi, uint64_t *bi_addr)
+ia64_platform_bootinfo(struct bootinfo *bi, struct bootinfo **res)
{
static struct bootinfo bootinfo;
@@ -58,17 +65,16 @@ ldr_bootinfo(struct bootinfo *bi, uint64_t *bi_addr)
sal_stub_init();
acpi_stub_init();
- *bi_addr = (uint64_t)(&bootinfo);
- bootinfo = *bi;
+ *res = &bootinfo;
return (0);
}
int
-ldr_enter(const char *kernel)
+ia64_platform_enter(const char *kernel)
{
while (*kernel == '/')
kernel++;
- ssc(0, (uint64_t)kernel, 0, 0, SSC_LOAD_SYMBOLS);
+ ssc(0, (uint64_t)kernel, 0, 0, SSC_LOAD_SYMBOLS);
return (0);
}
diff --git a/sys/boot/ia64/ski/version b/sys/boot/ia64/ski/version
index afa69ea..a5b40f5 100644
--- a/sys/boot/ia64/ski/version
+++ b/sys/boot/ia64/ski/version
@@ -3,6 +3,7 @@ $FreeBSD$
NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this
file is important. Make sure the current version number is on line 6.
+2.0: Add support for PBVM.
1.2: Restructured. Has some user visible differences. Due to code
sharing, has been given the same version number as the EFI
loader.
diff --git a/sys/ia64/include/bootinfo.h b/sys/ia64/include/bootinfo.h
index 2a065e9..6b14d1a 100644
--- a/sys/ia64/include/bootinfo.h
+++ b/sys/ia64/include/bootinfo.h
@@ -30,7 +30,8 @@ struct bootinfo {
uint64_t bi_magic; /* BOOTINFO_MAGIC */
#define BOOTINFO_MAGIC 0xdeadbeeffeedface
uint64_t bi_version; /* version 1 */
- uint64_t bi_spare[6]; /* was: name of booted kernel */
+ uint64_t bi_spare[5]; /* was: name of booted kernel */
+ uint64_t bi_pbvm_pgtbl; /* PA of PBVM page table. */
uint64_t bi_hcdp; /* DIG64 HCDP table */
uint64_t bi_fpswa; /* FPSWA interface */
uint64_t bi_boothowto; /* value for boothowto */
@@ -39,7 +40,7 @@ struct bootinfo {
uint64_t bi_memmap_size; /* size of EFI memory map */
uint64_t bi_memdesc_size; /* sizeof EFI memory desc */
uint32_t bi_memdesc_version; /* EFI memory desc version */
- uint32_t bi_spare2;
+ uint32_t bi_pbvm_pgtblsz; /* PBVM page table size. */
uint64_t bi_symtab; /* start of kernel sym table */
uint64_t bi_esymtab; /* end of kernel sym table */
uint64_t bi_kernend; /* end of kernel space */
diff --git a/sys/ia64/include/vmparam.h b/sys/ia64/include/vmparam.h
index edf5710..169b0c9 100644
--- a/sys/ia64/include/vmparam.h
+++ b/sys/ia64/include/vmparam.h
@@ -131,6 +131,16 @@
#define IA64_PHYS_TO_RR7(x) ((x) | IA64_RR_BASE(7))
/*
+ * The Itanium architecture defines that all implementations support at
+ * least 51 virtual address bits (i.e. IMPL_VA_MSB=50). The unimplemented
+ * bits are sign-extended from VA{IMPL_VA_MSB}. As such, there's a gap in
+ * the virtual address range, which extends at most from 0x0004000000000000
+ * to 0x1ffbffffffffffff. We define the top half of a region in terms of
+ * this worst-case gap.
+ */
+#define IA64_REGION_TOP_HALF 0x1ffc000000000000
+
+/*
* Page size of the identity mappings in region 7.
*/
#ifndef LOG2_ID_PAGE_SIZE
@@ -144,6 +154,42 @@
#define IA64_BACKINGSTORE IA64_RR_BASE(4)
/*
+ * Parameters for Pre-Boot Virtual Memory (PBVM).
+ * The kernel, its modules and metadata are loaded in the PBVM by the loader.
+ * The PBVM consists of pages for which the mapping is maintained in a page
+ * table. The page table is at least 1 EFI page large (i.e. 4KB), but can be
+ * larger to accommodate more PBVM. The maximum page table size is 1MB. With
+ * 8 bytes per page table entry, this means that the PBVM has at least 512
+ * pages and at most 128K pages.
+ * The GNU toolchain (in particular GNU ld) does not support an alignment
+ * larger than 64K. This means that we cannot guarantee page alignment for
+ * a page size that's larger than 64K. We do want to have text and data in
+ * different pages, which means that the maximum usable page size is 64KB.
+ * Consequently:
+ * The maximum total PBVM size is 8GB -- enough for a DVD image. A page table
+ * of a single EFI page (4KB) allows for 32MB of PBVM.
+ *
+ * The kernel is given the PA and size of the page table that provides the
+ * mapping of the PBVM. The page table itself is assumed to be mapped at a
+ * known virtual address and using a single translation wired into the CPU.
+ * As such, the page table is assumed to be a power of 2 and naturally aligned.
+ * The kernel also assumes that a good portion of the kernel text is mapped
+ * and wired into the CPU, but does not assume that the mapping covers the
+ * whole of PBVM.
+ */
+#define IA64_PBVM_RR 4
+#define IA64_PBVM_BASE \
+ (IA64_RR_BASE(IA64_PBVM_RR) + IA64_REGION_TOP_HALF)
+
+#define IA64_PBVM_PGTBL_MAXSZ 1048576
+#define IA64_PBVM_PGTBL \
+ (IA64_RR_BASE(IA64_PBVM_RR + 1) - IA64_PBVM_PGTBL_MAXSZ)
+
+#define IA64_PBVM_PAGE_SHIFT 16 /* 64KB */
+#define IA64_PBVM_PAGE_SIZE (1 << IA64_PBVM_PAGE_SHIFT)
+#define IA64_PBVM_PAGE_MASK (IA64_PBVM_PAGE_SIZE - 1)
+
+/*
* Mach derived constants
*/
OpenPOWER on IntegriCloud