1139738Simp/*- 2164010Smarcel * Copyright (c) 2004, 2006 Marcel Moolenaar 3138140Smarcel * All rights reserved. 4138140Smarcel * 5138140Smarcel * Redistribution and use in source and binary forms, with or without 6138140Smarcel * modification, are permitted provided that the following conditions 7138140Smarcel * are met: 8138140Smarcel * 9138140Smarcel * 1. Redistributions of source code must retain the above copyright 10138140Smarcel * notice, this list of conditions and the following disclaimer. 11138140Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12138140Smarcel * notice, this list of conditions and the following disclaimer in the 13138140Smarcel * documentation and/or other materials provided with the distribution. 14138140Smarcel * 15138140Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16138140Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17138140Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18138140Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19138140Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20138140Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21138140Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22138140Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23138140Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24138140Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25138140Smarcel */ 26138140Smarcel 27138140Smarcel#include <sys/cdefs.h> 28138140Smarcel__FBSDID("$FreeBSD$"); 29138140Smarcel 30164010Smarcel#include <stand.h> 31164010Smarcel 32138140Smarcel#include <efi.h> 33138140Smarcel#include <efilib.h> 34138140Smarcel 35164010Smarcel#include <libia64.h> 36138140Smarcel 37164010Smarcel#define EFI_INTEL_FPSWA \ 38164010Smarcel {0xc41b6531,0x97b9,0x11d3,{0x9a,0x29,0x00,0x90,0x27,0x3f,0xc1,0x4d}} 39164010Smarcel 40164010Smarcelstatic EFI_GUID fpswa_guid = EFI_INTEL_FPSWA; 41164010Smarcel 42164010Smarcel/* DIG64 Headless Console & Debug Port Table. */ 43164010Smarcel#define HCDP_TABLE_GUID \ 44164010Smarcel {0xf951938d,0x620b,0x42ef,{0x82,0x79,0xa8,0x4b,0x79,0x61,0x78,0x98}} 45164010Smarcel 46164010Smarcelstatic EFI_GUID hcdp_guid = HCDP_TABLE_GUID; 47164010Smarcel 48219691Smarcelstatic EFI_MEMORY_DESCRIPTOR *memmap; 49219691Smarcelstatic UINTN memmapsz; 50164010Smarcelstatic UINTN mapkey; 51219691Smarcelstatic UINTN descsz; 52219691Smarcelstatic UINT32 descver; 53164010Smarcel 54219691Smarcel#define IA64_EFI_CHUNK_SIZE (32 * 1048576) 55219691Smarcelstatic vm_paddr_t ia64_efi_chunk; 56219691Smarcel 57219691Smarcel#define IA64_EFI_PGTBLSZ_MAX 1048576 58219691Smarcelstatic vm_paddr_t ia64_efi_pgtbl; 59219691Smarcelstatic vm_size_t ia64_efi_pgtblsz; 60219691Smarcel 61219691Smarcel/* Don't allocate memory below the boundary */ 62219691Smarcel#define IA64_EFI_ALLOC_BOUNDARY 1048576 63219691Smarcel 64219691Smarcelstatic int 65219691Smarcelia64_efi_memmap_update(void) 66138140Smarcel{ 67219691Smarcel EFI_STATUS status; 68138140Smarcel 69219691Smarcel if (memmap != NULL) { 70219691Smarcel free(memmap); 71219691Smarcel memmap = NULL; 72219691Smarcel } 73219691Smarcel 74219691Smarcel memmapsz = 0; 75219691Smarcel BS->GetMemoryMap(&memmapsz, NULL, &mapkey, &descsz, &descver); 76219691Smarcel if (memmapsz == 0) 77219691Smarcel return (FALSE); 78219691Smarcel memmap = malloc(memmapsz); 79219691Smarcel if (memmap == NULL) 80219691Smarcel return (FALSE); 81219691Smarcel 82219691Smarcel status = BS->GetMemoryMap(&memmapsz, memmap, &mapkey, &descsz, 83219691Smarcel &descver); 84219691Smarcel if (EFI_ERROR(status)) { 85219691Smarcel free(memmap); 86219691Smarcel memmap = NULL; 87219691Smarcel return (FALSE); 88219691Smarcel } 89219691Smarcel 90219691Smarcel return (TRUE); 91219691Smarcel} 92219691Smarcel 93221269Smarcel/* 94221269Smarcel * Returns 0 on failure. Successful allocations return an address 95221269Smarcel * larger or equal to IA64_EFI_ALLOC_BOUNDARY. 96221269Smarcel */ 97219691Smarcelstatic vm_paddr_t 98219691Smarcelia64_efi_alloc(vm_size_t sz) 99219691Smarcel{ 100219691Smarcel EFI_PHYSICAL_ADDRESS pa; 101219691Smarcel EFI_MEMORY_DESCRIPTOR *mm; 102219691Smarcel uint8_t *mmiter, *mmiterend; 103219691Smarcel vm_size_t memsz; 104219691Smarcel UINTN npgs; 105219691Smarcel EFI_STATUS status; 106219691Smarcel 107219691Smarcel /* We can't allocate less than a page */ 108219691Smarcel if (sz < EFI_PAGE_SIZE) 109219691Smarcel return (0); 110219691Smarcel 111219691Smarcel /* The size must be a power of 2. */ 112219691Smarcel if (sz & (sz - 1)) 113219691Smarcel return (0); 114219691Smarcel 115219691Smarcel if (!ia64_efi_memmap_update()) 116219691Smarcel return (0); 117219691Smarcel 118219691Smarcel mmiter = (void *)memmap; 119219691Smarcel mmiterend = mmiter + memmapsz; 120219691Smarcel for (; mmiter < mmiterend; mmiter += descsz) { 121219691Smarcel mm = (void *)mmiter; 122219691Smarcel if (mm->Type != EfiConventionalMemory) 123219691Smarcel continue; 124219691Smarcel memsz = mm->NumberOfPages * EFI_PAGE_SIZE; 125219691Smarcel if (mm->PhysicalStart + memsz <= IA64_EFI_ALLOC_BOUNDARY) 126219691Smarcel continue; 127219691Smarcel /* 128219691Smarcel * XXX We really should make sure the memory is local to the 129219691Smarcel * BSP. 130219691Smarcel */ 131219691Smarcel pa = (mm->PhysicalStart < IA64_EFI_ALLOC_BOUNDARY) ? 132219691Smarcel IA64_EFI_ALLOC_BOUNDARY : mm->PhysicalStart; 133219691Smarcel pa = (pa + sz - 1) & ~(sz - 1); 134219691Smarcel if (pa + sz > mm->PhysicalStart + memsz) 135219691Smarcel continue; 136219691Smarcel 137219691Smarcel npgs = EFI_SIZE_TO_PAGES(sz); 138219691Smarcel status = BS->AllocatePages(AllocateAddress, EfiLoaderData, 139219691Smarcel npgs, &pa); 140219691Smarcel if (!EFI_ERROR(status)) 141219691Smarcel return (pa); 142219691Smarcel } 143219691Smarcel 144219691Smarcel printf("%s: unable to allocate %lx bytes\n", __func__, sz); 145164010Smarcel return (0); 146138140Smarcel} 147164010Smarcel 148219691Smarcelvm_paddr_t 149219691Smarcelia64_platform_alloc(vm_offset_t va, vm_size_t sz) 150219691Smarcel{ 151221269Smarcel vm_paddr_t pa; 152219691Smarcel 153219691Smarcel if (va == 0) { 154219691Smarcel /* Page table itself. */ 155219691Smarcel if (sz > IA64_EFI_PGTBLSZ_MAX) 156221269Smarcel return (~0UL); 157219691Smarcel if (ia64_efi_pgtbl == 0) 158219691Smarcel ia64_efi_pgtbl = ia64_efi_alloc(IA64_EFI_PGTBLSZ_MAX); 159219691Smarcel if (ia64_efi_pgtbl != 0) 160219691Smarcel ia64_efi_pgtblsz = sz; 161219691Smarcel return (ia64_efi_pgtbl); 162219691Smarcel } else if (va < IA64_PBVM_BASE) { 163219691Smarcel /* Should not happen. */ 164221269Smarcel return (~0UL); 165219691Smarcel } 166219691Smarcel 167219691Smarcel /* Loader virtual memory page. */ 168219691Smarcel va -= IA64_PBVM_BASE; 169219691Smarcel 170219691Smarcel /* Allocate a big chunk that can be wired with a single PTE. */ 171219691Smarcel if (ia64_efi_chunk == 0) 172219691Smarcel ia64_efi_chunk = ia64_efi_alloc(IA64_EFI_CHUNK_SIZE); 173219691Smarcel if (va < IA64_EFI_CHUNK_SIZE) 174219691Smarcel return (ia64_efi_chunk + va); 175219691Smarcel 176219691Smarcel /* Allocate a page at a time when we go beyond the chunk. */ 177221269Smarcel pa = ia64_efi_alloc(sz); 178221269Smarcel return ((pa == 0) ? ~0UL : pa); 179219691Smarcel} 180219691Smarcel 181219691Smarcelvoid 182219691Smarcelia64_platform_free(vm_offset_t va, vm_paddr_t pa, vm_size_t sz) 183219691Smarcel{ 184219691Smarcel 185219691Smarcel BS->FreePages(pa, sz >> EFI_PAGE_SHIFT); 186219691Smarcel} 187219691Smarcel 188164010Smarcelint 189219691Smarcelia64_platform_bootinfo(struct bootinfo *bi, struct bootinfo **res) 190164010Smarcel{ 191164010Smarcel VOID *fpswa; 192164010Smarcel EFI_HANDLE handle; 193164010Smarcel EFI_STATUS status; 194219691Smarcel UINTN sz; 195164010Smarcel 196164010Smarcel bi->bi_systab = (uint64_t)ST; 197164010Smarcel bi->bi_hcdp = (uint64_t)efi_get_table(&hcdp_guid); 198164010Smarcel 199164010Smarcel sz = sizeof(EFI_HANDLE); 200164010Smarcel status = BS->LocateHandle(ByProtocol, &fpswa_guid, 0, &sz, &handle); 201164010Smarcel if (status == 0) 202164010Smarcel status = BS->HandleProtocol(handle, &fpswa_guid, &fpswa); 203164010Smarcel bi->bi_fpswa = (status == 0) ? (uint64_t)fpswa : 0; 204164010Smarcel 205219691Smarcel if (!ia64_efi_memmap_update()) 206164010Smarcel return (ENOMEM); 207164010Smarcel 208219691Smarcel bi->bi_memmap = (uint64_t)memmap; 209219691Smarcel bi->bi_memmap_size = memmapsz; 210219691Smarcel bi->bi_memdesc_size = descsz; 211219691Smarcel bi->bi_memdesc_version = descver; 212164010Smarcel 213219691Smarcel if (IS_LEGACY_KERNEL()) 214219691Smarcel *res = malloc(sizeof(**res)); 215219691Smarcel 216164010Smarcel return (0); 217164010Smarcel} 218164010Smarcel 219164010Smarcelint 220219691Smarcelia64_platform_enter(const char *kernel) 221164010Smarcel{ 222164010Smarcel EFI_STATUS status; 223164010Smarcel 224164010Smarcel status = BS->ExitBootServices(IH, mapkey); 225164010Smarcel if (EFI_ERROR(status)) { 226164010Smarcel printf("%s: ExitBootServices() returned 0x%lx\n", __func__, 227164010Smarcel (long)status); 228164010Smarcel return (EINVAL); 229164010Smarcel } 230164010Smarcel 231164010Smarcel return (0); 232164010Smarcel} 233222799Smarcel 234222799SmarcelCOMMAND_SET(pbvm, "pbvm", "show PBVM details", command_pbvm); 235222799Smarcel 236222799Smarcelstatic int 237222799Smarcelcommand_pbvm(int argc, char *argv[]) 238222799Smarcel{ 239222799Smarcel uint64_t limit, pg, start; 240222799Smarcel u_int idx; 241222799Smarcel 242222799Smarcel printf("Page table @ %p, size %x\n", ia64_pgtbl, ia64_pgtblsz); 243222799Smarcel 244222799Smarcel if (ia64_pgtbl == NULL) 245222799Smarcel return (0); 246222799Smarcel 247222799Smarcel limit = ~0; 248222799Smarcel start = ~0; 249222799Smarcel idx = 0; 250222799Smarcel while (ia64_pgtbl[idx] != 0) { 251222799Smarcel pg = ia64_pgtbl[idx]; 252222799Smarcel if (pg != limit) { 253222799Smarcel if (start != ~0) 254222799Smarcel printf("%#lx-%#lx\n", start, limit); 255222799Smarcel start = pg; 256222799Smarcel } 257222799Smarcel limit = pg + IA64_PBVM_PAGE_SIZE; 258222799Smarcel idx++; 259222799Smarcel } 260222799Smarcel if (start != ~0) 261222799Smarcel printf("%#lx-%#lx\n", start, limit); 262222799Smarcel 263222799Smarcel return (0); 264222799Smarcel} 265