diff options
author | marcel <marcel@FreeBSD.org> | 2011-03-16 03:53:18 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2011-03-16 03:53:18 +0000 |
commit | 8e0b0a22844d3d1383011c024b1eb1a3b2ee51a8 (patch) | |
tree | 55215f77e655236a449e347f8f98d98dfb718eed /sys/boot/ia64/efi | |
parent | e79931d6175d1a1999786ee313a144784de8d6a9 (diff) | |
download | FreeBSD-src-8e0b0a22844d3d1383011c024b1eb1a3b2ee51a8.zip FreeBSD-src-8e0b0a22844d3d1383011c024b1eb1a3b2ee51a8.tar.gz |
MFaltix:
Add support for Pre-Boot Virtual Memory (PBVM) to the loader.
PBVM allows us to link the kernel at a fixed virtual address without
having to make any assumptions about the physical memory layout. On
the SGI Altix 350 for example, there's no usuable physical memory
below 192GB. Also, the PBVM allows us to control better where we're
going to physically load the kernel and its modules so that we can
make sure we load the kernel in memory that's close to the BSP.
The PBVM is managed by a simple page table. The minimum size of the
page table is 4KB (EFI page size) and the maximum is currently set
to 1MB. A page in the PBVM is 64KB, as that's the maximum alignment
one can specify in a linker script. The bottom line is that PBVM is
between 64KB and 8GB in size.
The loader maps the PBVM page table at a fixed virtual address and
using a single translations. The PBVM itself is also mapped using a
single translation for a maximum of 32MB.
While here, increase the heap in the EFI loader from 512KB to 2MB
and set the stage for supporting relocatable modules.
Diffstat (limited to 'sys/boot/ia64/efi')
-rw-r--r-- | sys/boot/ia64/efi/conf.c | 11 | ||||
-rw-r--r-- | sys/boot/ia64/efi/efimd.c | 188 | ||||
-rw-r--r-- | sys/boot/ia64/efi/version | 1 |
3 files changed, 139 insertions, 61 deletions
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. |