copy.c revision 219691
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 219691 2011-03-16 03:53:18Z marcel $"); 29 30#include <stand.h> 31#include <ia64/include/vmparam.h> 32 33#include "libia64.h" 34 35uint64_t *ia64_pgtbl; 36uint32_t ia64_pgtblsz; 37 38static int 39pgtbl_extend(u_int idx) 40{ 41 uint64_t *pgtbl; 42 uint32_t pgtblsz; 43 u_int pot; 44 45 pgtblsz = (idx + 1) << 3; 46 47 /* The minimum size is 4KB. */ 48 if (pgtblsz < 4096) 49 pgtblsz = 4096; 50 51 /* Find the next higher power of 2. */ 52 pgtblsz--; 53 for (pot = 1; pot < 32; pot <<= 1) 54 pgtblsz = pgtblsz | (pgtblsz >> pot); 55 pgtblsz++; 56 57 /* The maximum size is 1MB. */ 58 if (pgtblsz > 1048576) 59 return (ENOMEM); 60 61 /* Make sure the size is a valid (mappable) page size. */ 62 if (pgtblsz == 32*1024 || pgtblsz == 128*1024 || pgtblsz == 512*1024) 63 pgtblsz <<= 1; 64 65 /* Allocate naturally aligned memory. */ 66 pgtbl = (void *)ia64_platform_alloc(0, pgtblsz); 67 if (pgtbl == NULL) 68 return (ENOMEM); 69 70 /* Initialize new page table. */ 71 if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl) 72 bcopy(ia64_pgtbl, pgtbl, ia64_pgtblsz); 73 bzero(pgtbl + (ia64_pgtblsz >> 3), pgtblsz - ia64_pgtblsz); 74 75 if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl) 76 ia64_platform_free(0, (uintptr_t)ia64_pgtbl, ia64_pgtblsz); 77 78 ia64_pgtbl = pgtbl; 79 ia64_pgtblsz = pgtblsz; 80 return (0); 81} 82 83static void * 84va2pa(vm_offset_t va, size_t *len) 85{ 86 uint64_t pa; 87 u_int idx, ofs; 88 int error; 89 90 /* Backward compatibility. */ 91 if (va >= IA64_RR_BASE(7)) { 92 pa = IA64_RR_MASK(va); 93 return ((void *)pa); 94 } 95 96 if (va < IA64_PBVM_BASE) { 97 error = EINVAL; 98 goto fail; 99 } 100 101 idx = (va - IA64_PBVM_BASE) >> IA64_PBVM_PAGE_SHIFT; 102 if (idx >= (ia64_pgtblsz >> 3)) { 103 error = pgtbl_extend(idx); 104 if (error) 105 goto fail; 106 } 107 108 ofs = va & IA64_PBVM_PAGE_MASK; 109 pa = ia64_pgtbl[idx]; 110 if (pa == 0) { 111 pa = ia64_platform_alloc(va - ofs, IA64_PBVM_PAGE_SIZE); 112 if (pa == 0) { 113 error = ENOMEM; 114 goto fail; 115 } 116 ia64_pgtbl[idx] = pa; 117 } 118 pa += ofs; 119 120 /* We can not cross page boundaries (in general). */ 121 if (*len + ofs > IA64_PBVM_PAGE_SIZE) 122 *len = IA64_PBVM_PAGE_SIZE - ofs; 123 124 return ((void *)pa); 125 126 fail: 127 *len = 0; 128 return (NULL); 129} 130 131ssize_t 132ia64_copyin(const void *src, vm_offset_t va, size_t len) 133{ 134 void *pa; 135 ssize_t res; 136 size_t sz; 137 138 res = 0; 139 while (len > 0) { 140 sz = len; 141 pa = va2pa(va, &sz); 142 if (sz == 0) 143 break; 144 bcopy(src, pa, sz); 145 len -= sz; 146 res += sz; 147 va += sz; 148 } 149 return (res); 150} 151 152ssize_t 153ia64_copyout(vm_offset_t va, void *dst, size_t len) 154{ 155 void *pa; 156 ssize_t res; 157 size_t sz; 158 159 res = 0; 160 while (len > 0) { 161 sz = len; 162 pa = va2pa(va, &sz); 163 if (sz == 0) 164 break; 165 bcopy(pa, dst, sz); 166 len -= sz; 167 res += sz; 168 va += sz; 169 } 170 return (res); 171} 172 173ssize_t 174ia64_readin(int fd, vm_offset_t va, size_t len) 175{ 176 void *pa; 177 ssize_t res, s; 178 size_t sz; 179 180 res = 0; 181 while (len > 0) { 182 sz = len; 183 pa = va2pa(va, &sz); 184 if (sz == 0) 185 break; 186 s = read(fd, pa, sz); 187 if (s <= 0) 188 break; 189 len -= s; 190 res += s; 191 va += s; 192 } 193 return (res); 194} 195