Index: head/sys/boot/ia64/common/copy.c =================================================================== --- head/sys/boot/ia64/common/copy.c (revision 221268) +++ head/sys/boot/ia64/common/copy.c (revision 221269) @@ -1,212 +1,217 @@ /*- * Copyright (c) 2006 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include +#include #include "libia64.h" u_int ia64_legacy_kernel; uint64_t *ia64_pgtbl; uint32_t ia64_pgtblsz; static int pgtbl_extend(u_int idx) { + vm_paddr_t pa; 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) + pa = ia64_platform_alloc(0, pgtblsz); + if (pa == ~0UL) return (ENOMEM); + pgtbl = (void *)pa; /* 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); } void * ia64_va2pa(vm_offset_t va, size_t *len) { - uint64_t pa; + uint64_t pa, pte; u_int idx, ofs; int error; /* Backward compatibility. */ if (va >= IA64_RR_BASE(7)) { ia64_legacy_kernel = 1; pa = IA64_RR_MASK(va); return ((void *)pa); } if (va < IA64_PBVM_BASE) { error = EINVAL; goto fail; } ia64_legacy_kernel = 0; 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) { + pte = ia64_pgtbl[idx]; + if ((pte & PTE_PRESENT) == 0) { pa = ia64_platform_alloc(va - ofs, IA64_PBVM_PAGE_SIZE); - if (pa == 0) { + if (pa == ~0UL) { error = ENOMEM; goto fail; } - ia64_pgtbl[idx] = pa; + pte = PTE_AR_RWX | PTE_DIRTY | PTE_ACCESSED | PTE_PRESENT; + pte |= (pa & PTE_PPN_MASK); + ia64_pgtbl[idx] = pte; } - pa += ofs; + pa = (pte & PTE_PPN_MASK) + 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); } ssize_t ia64_copyin(const void *src, vm_offset_t va, size_t len) { void *pa; ssize_t res; size_t sz; res = 0; while (len > 0) { sz = len; pa = ia64_va2pa(va, &sz); if (sz == 0) break; bcopy(src, pa, sz); len -= sz; res += sz; va += sz; } return (res); } ssize_t ia64_copyout(vm_offset_t va, void *dst, size_t len) { void *pa; ssize_t res; size_t sz; res = 0; while (len > 0) { sz = len; pa = ia64_va2pa(va, &sz); if (sz == 0) break; bcopy(pa, dst, sz); len -= sz; res += sz; va += sz; } return (res); } uint64_t ia64_loadaddr(u_int type, void *data, uint64_t addr) { uint64_t align; /* * Align ELF objects at PBVM page boundaries. Align all other * objects at cache line boundaries for good measure. */ align = (type == LOAD_ELF) ? IA64_PBVM_PAGE_SIZE : CACHE_LINE_SIZE; return ((addr + align - 1) & ~(align - 1)); } ssize_t ia64_readin(int fd, vm_offset_t va, size_t len) { void *pa; ssize_t res, s; size_t sz; res = 0; while (len > 0) { sz = len; pa = ia64_va2pa(va, &sz); if (sz == 0) break; s = read(fd, pa, sz); if (s <= 0) break; len -= s; res += s; va += s; } return (res); } Index: head/sys/boot/ia64/efi/efimd.c =================================================================== --- head/sys/boot/ia64/efi/efimd.c (revision 221268) +++ head/sys/boot/ia64/efi/efimd.c (revision 221269) @@ -1,226 +1,232 @@ /*- * Copyright (c) 2004, 2006 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #define EFI_INTEL_FPSWA \ {0xc41b6531,0x97b9,0x11d3,{0x9a,0x29,0x00,0x90,0x27,0x3f,0xc1,0x4d}} static EFI_GUID fpswa_guid = EFI_INTEL_FPSWA; /* DIG64 Headless Console & Debug Port Table. */ #define HCDP_TABLE_GUID \ {0xf951938d,0x620b,0x42ef,{0x82,0x79,0xa8,0x4b,0x79,0x61,0x78,0x98}} 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; #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); } +/* + * Returns 0 on failure. Successful allocations return an address + * larger or equal to IA64_EFI_ALLOC_BOUNDARY. + */ 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) { + vm_paddr_t pa; if (va == 0) { /* Page table itself. */ if (sz > IA64_EFI_PGTBLSZ_MAX) - return (0); + return (~0UL); 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); + return (~0UL); } /* 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)); + pa = ia64_efi_alloc(sz); + return ((pa == 0) ? ~0UL : pa); } void ia64_platform_free(vm_offset_t va, vm_paddr_t pa, vm_size_t sz) { BS->FreePages(pa, sz >> EFI_PAGE_SHIFT); } int ia64_platform_bootinfo(struct bootinfo *bi, struct bootinfo **res) { VOID *fpswa; EFI_HANDLE handle; EFI_STATUS status; UINTN sz; bi->bi_systab = (uint64_t)ST; bi->bi_hcdp = (uint64_t)efi_get_table(&hcdp_guid); sz = sizeof(EFI_HANDLE); status = BS->LocateHandle(ByProtocol, &fpswa_guid, 0, &sz, &handle); if (status == 0) status = BS->HandleProtocol(handle, &fpswa_guid, &fpswa); bi->bi_fpswa = (status == 0) ? (uint64_t)fpswa : 0; if (!ia64_efi_memmap_update()) return (ENOMEM); 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)); return (0); } int ia64_platform_enter(const char *kernel) { EFI_STATUS status; status = BS->ExitBootServices(IH, mapkey); if (EFI_ERROR(status)) { printf("%s: ExitBootServices() returned 0x%lx\n", __func__, (long)status); return (EINVAL); } return (0); }