1 /*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 /* 31 * MD primitives supporting placement of module data 32 * 33 * XXX should check load address/size against memory top. 34 */ 35 #include <stand.h> 36 37 #include "libofw.h" 38 39 #define READIN_BUF (4 * 1024) 40 #define PAGE_SIZE 0x1000 41 #define PAGE_MASK 0x0fff 42 #define MAPMEM_PAGE_INC 128 /* Half-MB at a time */ 43 44 45 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 46 47 static int 48 ofw_mapmem(vm_offset_t dest, const size_t len) 49 { 50 void *destp, *addr; 51 size_t dlen; 52 size_t resid; 53 size_t nlen; 54 static vm_offset_t last_dest = 0; 55 static size_t last_len = 0; 56 57 nlen = len; 58 /* 59 * Check to see if this region fits in a prior mapping. 60 * Allocations are generally sequential, so only check 61 * the last one. 62 */ 63 if (dest >= last_dest && 64 (dest + len) <= (last_dest + last_len)) { 65 return (0); 66 } 67 68 /* 69 * Trim area covered by existing mapping, if any 70 */ 71 if (dest < (last_dest + last_len) && dest >= last_dest) { 72 nlen -= (last_dest + last_len) - dest; 73 dest = last_dest + last_len; 74 } 75 76 destp = (void *)(dest & ~PAGE_MASK); 77 resid = dest & PAGE_MASK; 78 79 /* 80 * To avoid repeated mappings on small allocations, 81 * never map anything less than MAPMEM_PAGE_INC pages at a time 82 */ 83 if ((nlen + resid) < PAGE_SIZE*MAPMEM_PAGE_INC) { 84 dlen = PAGE_SIZE*MAPMEM_PAGE_INC; 85 } else 86 dlen = roundup(nlen + resid, PAGE_SIZE); 87 88 if (OF_call_method("claim", memory, 3, 1, destp, dlen, 0, &addr) 89 == -1) { 90 printf("ofw_mapmem: physical claim failed\n"); 91 return (ENOMEM); 92 } 93 94 /* 95 * We only do virtual memory management when real_mode is false. 96 */ 97 if (real_mode == 0) { 98 if (OF_call_method("claim", mmu, 3, 1, destp, dlen, 0, &addr) 99 == -1) { 100 printf("ofw_mapmem: virtual claim failed\n"); 101 return (ENOMEM); 102 } 103 104 if (OF_call_method("map", mmu, 4, 0, destp, destp, dlen, 0) 105 == -1) { 106 printf("ofw_mapmem: map failed\n"); 107 return (ENOMEM); 108 } 109 } 110 last_dest = (vm_offset_t) destp; 111 last_len = dlen; 112 113 return (0); 114 } 115 116 ssize_t 117 ofw_copyin(const void *src, vm_offset_t dest, const size_t len) 118 { 119 if (ofw_mapmem(dest, len)) { 120 printf("ofw_copyin: map error\n"); 121 return (0); 122 } 123 124 bcopy(src, (void *)dest, len); 125 return(len); 126 } 127 128 ssize_t 129 ofw_copyout(const vm_offset_t src, void *dest, const size_t len) 130 { 131 bcopy((void *)src, dest, len); 132 return(len); 133 } 134 135 ssize_t 136 ofw_readin(readin_handle_t fd, vm_offset_t dest, const size_t len) 137 { 138 void *buf; 139 size_t resid, chunk, get; 140 ssize_t got; 141 vm_offset_t p; 142 143 p = dest; 144 145 chunk = min(READIN_BUF, len); 146 buf = malloc(chunk); 147 if (buf == NULL) { 148 printf("ofw_readin: buf malloc failed\n"); 149 return(0); 150 } 151 152 if (ofw_mapmem(dest, len)) { 153 printf("ofw_readin: map error\n"); 154 free(buf); 155 return (0); 156 } 157 158 for (resid = len; resid > 0; resid -= got, p += got) { 159 get = min(chunk, resid); 160 got = VECTX_READ(fd, buf, get); 161 162 if (got <= 0) { 163 if (got < 0) 164 printf("ofw_readin: read failed\n"); 165 break; 166 } 167 168 bcopy(buf, (void *)p, got); 169 } 170 171 free(buf); 172 return(len - resid); 173 } 174