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