copy.c revision 220313
177943Sdfr/*- 2164010Smarcel * Copyright (c) 2006 Marcel Moolenaar 377943Sdfr * All rights reserved. 477943Sdfr * 577943Sdfr * Redistribution and use in source and binary forms, with or without 677943Sdfr * modification, are permitted provided that the following conditions 777943Sdfr * are met: 8164010Smarcel * 977943Sdfr * 1. Redistributions of source code must retain the above copyright 1077943Sdfr * notice, this list of conditions and the following disclaimer. 1177943Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1277943Sdfr * notice, this list of conditions and the following disclaimer in the 1377943Sdfr * documentation and/or other materials provided with the distribution. 1477943Sdfr * 15164010Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16164010Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17164010Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18164010Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19164010Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20164010Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21164010Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22164010Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23164010Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24164010Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2577943Sdfr */ 2678320Sobrien 27113038Sobrien#include <sys/cdefs.h> 28113038Sobrien__FBSDID("$FreeBSD: head/sys/boot/ia64/common/copy.c 220313 2011-04-03 23:49:20Z marcel $"); 2978320Sobrien 30138141Smarcel#include <stand.h> 31220313Smarcel#include <machine/param.h> 3277943Sdfr 33164010Smarcel#include "libia64.h" 34164010Smarcel 35220313Smarcelu_int ia64_legacy_kernel; 36220313Smarcel 37219691Smarceluint64_t *ia64_pgtbl; 38219691Smarceluint32_t ia64_pgtblsz; 39219691Smarcel 40219691Smarcelstatic int 41219691Smarcelpgtbl_extend(u_int idx) 42219691Smarcel{ 43219691Smarcel uint64_t *pgtbl; 44219691Smarcel uint32_t pgtblsz; 45219691Smarcel u_int pot; 46219691Smarcel 47219691Smarcel pgtblsz = (idx + 1) << 3; 48219691Smarcel 49219691Smarcel /* The minimum size is 4KB. */ 50219691Smarcel if (pgtblsz < 4096) 51219691Smarcel pgtblsz = 4096; 52219691Smarcel 53219691Smarcel /* Find the next higher power of 2. */ 54219691Smarcel pgtblsz--; 55219691Smarcel for (pot = 1; pot < 32; pot <<= 1) 56219691Smarcel pgtblsz = pgtblsz | (pgtblsz >> pot); 57219691Smarcel pgtblsz++; 58219691Smarcel 59219691Smarcel /* The maximum size is 1MB. */ 60219691Smarcel if (pgtblsz > 1048576) 61219691Smarcel return (ENOMEM); 62219691Smarcel 63219691Smarcel /* Make sure the size is a valid (mappable) page size. */ 64219691Smarcel if (pgtblsz == 32*1024 || pgtblsz == 128*1024 || pgtblsz == 512*1024) 65219691Smarcel pgtblsz <<= 1; 66219691Smarcel 67219691Smarcel /* Allocate naturally aligned memory. */ 68219691Smarcel pgtbl = (void *)ia64_platform_alloc(0, pgtblsz); 69219691Smarcel if (pgtbl == NULL) 70219691Smarcel return (ENOMEM); 71219691Smarcel 72219691Smarcel /* Initialize new page table. */ 73219691Smarcel if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl) 74219691Smarcel bcopy(ia64_pgtbl, pgtbl, ia64_pgtblsz); 75219691Smarcel bzero(pgtbl + (ia64_pgtblsz >> 3), pgtblsz - ia64_pgtblsz); 76219691Smarcel 77219691Smarcel if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl) 78219691Smarcel ia64_platform_free(0, (uintptr_t)ia64_pgtbl, ia64_pgtblsz); 79219691Smarcel 80219691Smarcel ia64_pgtbl = pgtbl; 81219691Smarcel ia64_pgtblsz = pgtblsz; 82219691Smarcel return (0); 83219691Smarcel} 84219691Smarcel 85220313Smarcelvoid * 86220313Smarcelia64_va2pa(vm_offset_t va, size_t *len) 8777943Sdfr{ 88164010Smarcel uint64_t pa; 89219691Smarcel u_int idx, ofs; 90219691Smarcel int error; 91138141Smarcel 92219691Smarcel /* Backward compatibility. */ 93164010Smarcel if (va >= IA64_RR_BASE(7)) { 94220313Smarcel ia64_legacy_kernel = 1; 95164010Smarcel pa = IA64_RR_MASK(va); 96164010Smarcel return ((void *)pa); 97164010Smarcel } 98164010Smarcel 99219691Smarcel if (va < IA64_PBVM_BASE) { 100219691Smarcel error = EINVAL; 101219691Smarcel goto fail; 102219691Smarcel } 103219691Smarcel 104220313Smarcel ia64_legacy_kernel = 0; 105220313Smarcel 106219691Smarcel idx = (va - IA64_PBVM_BASE) >> IA64_PBVM_PAGE_SHIFT; 107219691Smarcel if (idx >= (ia64_pgtblsz >> 3)) { 108219691Smarcel error = pgtbl_extend(idx); 109219691Smarcel if (error) 110219691Smarcel goto fail; 111219691Smarcel } 112219691Smarcel 113219691Smarcel ofs = va & IA64_PBVM_PAGE_MASK; 114219691Smarcel pa = ia64_pgtbl[idx]; 115219691Smarcel if (pa == 0) { 116219691Smarcel pa = ia64_platform_alloc(va - ofs, IA64_PBVM_PAGE_SIZE); 117219691Smarcel if (pa == 0) { 118219691Smarcel error = ENOMEM; 119219691Smarcel goto fail; 120219691Smarcel } 121219691Smarcel ia64_pgtbl[idx] = pa; 122219691Smarcel } 123219691Smarcel pa += ofs; 124219691Smarcel 125219691Smarcel /* We can not cross page boundaries (in general). */ 126219691Smarcel if (*len + ofs > IA64_PBVM_PAGE_SIZE) 127219691Smarcel *len = IA64_PBVM_PAGE_SIZE - ofs; 128219691Smarcel 129219691Smarcel return ((void *)pa); 130219691Smarcel 131219691Smarcel fail: 132164010Smarcel *len = 0; 133164010Smarcel return (NULL); 13477943Sdfr} 13577943Sdfr 136164010Smarcelssize_t 137164010Smarcelia64_copyin(const void *src, vm_offset_t va, size_t len) 13877943Sdfr{ 139164010Smarcel void *pa; 140164010Smarcel ssize_t res; 141164010Smarcel size_t sz; 142138141Smarcel 143164010Smarcel res = 0; 144164010Smarcel while (len > 0) { 145164010Smarcel sz = len; 146220313Smarcel pa = ia64_va2pa(va, &sz); 147164010Smarcel if (sz == 0) 148164010Smarcel break; 149164010Smarcel bcopy(src, pa, sz); 150164010Smarcel len -= sz; 151164010Smarcel res += sz; 152164010Smarcel va += sz; 153164010Smarcel } 154164010Smarcel return (res); 15577943Sdfr} 15677943Sdfr 157164010Smarcelssize_t 158164010Smarcelia64_copyout(vm_offset_t va, void *dst, size_t len) 15977943Sdfr{ 160164010Smarcel void *pa; 161164010Smarcel ssize_t res; 162164010Smarcel size_t sz; 163138141Smarcel 164164010Smarcel res = 0; 165164010Smarcel while (len > 0) { 166164010Smarcel sz = len; 167220313Smarcel pa = ia64_va2pa(va, &sz); 168164010Smarcel if (sz == 0) 169164010Smarcel break; 170164010Smarcel bcopy(pa, dst, sz); 171164010Smarcel len -= sz; 172164010Smarcel res += sz; 173164010Smarcel va += sz; 174164010Smarcel } 175164010Smarcel return (res); 17677943Sdfr} 177164010Smarcel 178220313Smarceluint64_t 179220313Smarcelia64_loadaddr(u_int type, void *data, uint64_t addr) 180220313Smarcel{ 181220313Smarcel uint64_t align; 182220313Smarcel 183220313Smarcel /* 184220313Smarcel * Align ELF objects at PBVM page boundaries. Align all other 185220313Smarcel * objects at cache line boundaries for good measure. 186220313Smarcel */ 187220313Smarcel align = (type == LOAD_ELF) ? IA64_PBVM_PAGE_SIZE : CACHE_LINE_SIZE; 188220313Smarcel return ((addr + align - 1) & ~(align - 1)); 189220313Smarcel} 190220313Smarcel 191164010Smarcelssize_t 192164010Smarcelia64_readin(int fd, vm_offset_t va, size_t len) 193164010Smarcel{ 194164010Smarcel void *pa; 195164010Smarcel ssize_t res, s; 196164010Smarcel size_t sz; 197164010Smarcel 198164010Smarcel res = 0; 199164010Smarcel while (len > 0) { 200164010Smarcel sz = len; 201220313Smarcel pa = ia64_va2pa(va, &sz); 202164010Smarcel if (sz == 0) 203164010Smarcel break; 204164010Smarcel s = read(fd, pa, sz); 205164010Smarcel if (s <= 0) 206164010Smarcel break; 207164010Smarcel len -= s; 208164010Smarcel res += s; 209164010Smarcel va += s; 210164010Smarcel } 211164010Smarcel return (res); 212164010Smarcel} 213