copy.c revision 220313
1/*- 2 * Copyright (c) 2006 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/boot/ia64/common/copy.c 220313 2011-04-03 23:49:20Z marcel $"); 29 30#include <stand.h> 31#include <machine/param.h> 32 33#include "libia64.h" 34 35u_int ia64_legacy_kernel; 36 37uint64_t *ia64_pgtbl; 38uint32_t ia64_pgtblsz; 39 40static int 41pgtbl_extend(u_int idx) 42{ 43 uint64_t *pgtbl; 44 uint32_t pgtblsz; 45 u_int pot; 46 47 pgtblsz = (idx + 1) << 3; 48 49 /* The minimum size is 4KB. */ 50 if (pgtblsz < 4096) 51 pgtblsz = 4096; 52 53 /* Find the next higher power of 2. */ 54 pgtblsz--; 55 for (pot = 1; pot < 32; pot <<= 1) 56 pgtblsz = pgtblsz | (pgtblsz >> pot); 57 pgtblsz++; 58 59 /* The maximum size is 1MB. */ 60 if (pgtblsz > 1048576) 61 return (ENOMEM); 62 63 /* Make sure the size is a valid (mappable) page size. */ 64 if (pgtblsz == 32*1024 || pgtblsz == 128*1024 || pgtblsz == 512*1024) 65 pgtblsz <<= 1; 66 67 /* Allocate naturally aligned memory. */ 68 pgtbl = (void *)ia64_platform_alloc(0, pgtblsz); 69 if (pgtbl == NULL) 70 return (ENOMEM); 71 72 /* Initialize new page table. */ 73 if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl) 74 bcopy(ia64_pgtbl, pgtbl, ia64_pgtblsz); 75 bzero(pgtbl + (ia64_pgtblsz >> 3), pgtblsz - ia64_pgtblsz); 76 77 if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl) 78 ia64_platform_free(0, (uintptr_t)ia64_pgtbl, ia64_pgtblsz); 79 80 ia64_pgtbl = pgtbl; 81 ia64_pgtblsz = pgtblsz; 82 return (0); 83} 84 85void * 86ia64_va2pa(vm_offset_t va, size_t *len) 87{ 88 uint64_t pa; 89 u_int idx, ofs; 90 int error; 91 92 /* Backward compatibility. */ 93 if (va >= IA64_RR_BASE(7)) { 94 ia64_legacy_kernel = 1; 95 pa = IA64_RR_MASK(va); 96 return ((void *)pa); 97 } 98 99 if (va < IA64_PBVM_BASE) { 100 error = EINVAL; 101 goto fail; 102 } 103 104 ia64_legacy_kernel = 0; 105 106 idx = (va - IA64_PBVM_BASE) >> IA64_PBVM_PAGE_SHIFT; 107 if (idx >= (ia64_pgtblsz >> 3)) { 108 error = pgtbl_extend(idx); 109 if (error) 110 goto fail; 111 } 112 113 ofs = va & IA64_PBVM_PAGE_MASK; 114 pa = ia64_pgtbl[idx]; 115 if (pa == 0) { 116 pa = ia64_platform_alloc(va - ofs, IA64_PBVM_PAGE_SIZE); 117 if (pa == 0) { 118 error = ENOMEM; 119 goto fail; 120 } 121 ia64_pgtbl[idx] = pa; 122 } 123 pa += ofs; 124 125 /* We can not cross page boundaries (in general). */ 126 if (*len + ofs > IA64_PBVM_PAGE_SIZE) 127 *len = IA64_PBVM_PAGE_SIZE - ofs; 128 129 return ((void *)pa); 130 131 fail: 132 *len = 0; 133 return (NULL); 134} 135 136ssize_t 137ia64_copyin(const void *src, vm_offset_t va, size_t len) 138{ 139 void *pa; 140 ssize_t res; 141 size_t sz; 142 143 res = 0; 144 while (len > 0) { 145 sz = len; 146 pa = ia64_va2pa(va, &sz); 147 if (sz == 0) 148 break; 149 bcopy(src, pa, sz); 150 len -= sz; 151 res += sz; 152 va += sz; 153 } 154 return (res); 155} 156 157ssize_t 158ia64_copyout(vm_offset_t va, void *dst, size_t len) 159{ 160 void *pa; 161 ssize_t res; 162 size_t sz; 163 164 res = 0; 165 while (len > 0) { 166 sz = len; 167 pa = ia64_va2pa(va, &sz); 168 if (sz == 0) 169 break; 170 bcopy(pa, dst, sz); 171 len -= sz; 172 res += sz; 173 va += sz; 174 } 175 return (res); 176} 177 178uint64_t 179ia64_loadaddr(u_int type, void *data, uint64_t addr) 180{ 181 uint64_t align; 182 183 /* 184 * Align ELF objects at PBVM page boundaries. Align all other 185 * objects at cache line boundaries for good measure. 186 */ 187 align = (type == LOAD_ELF) ? IA64_PBVM_PAGE_SIZE : CACHE_LINE_SIZE; 188 return ((addr + align - 1) & ~(align - 1)); 189} 190 191ssize_t 192ia64_readin(int fd, vm_offset_t va, size_t len) 193{ 194 void *pa; 195 ssize_t res, s; 196 size_t sz; 197 198 res = 0; 199 while (len > 0) { 200 sz = len; 201 pa = ia64_va2pa(va, &sz); 202 if (sz == 0) 203 break; 204 s = read(fd, pa, sz); 205 if (s <= 0) 206 break; 207 len -= s; 208 res += s; 209 va += s; 210 } 211 return (res); 212} 213