ofw_copy.c revision 146368
138712Smsmith/*- 238712Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 338712Smsmith * All rights reserved. 438712Smsmith * 538712Smsmith * Redistribution and use in source and binary forms, with or without 638712Smsmith * modification, are permitted provided that the following conditions 738712Smsmith * are met: 838712Smsmith * 1. Redistributions of source code must retain the above copyright 938712Smsmith * notice, this list of conditions and the following disclaimer. 1038712Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1138712Smsmith * notice, this list of conditions and the following disclaimer in the 1238712Smsmith * documentation and/or other materials provided with the distribution. 1338712Smsmith * 1438712Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538712Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638712Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738712Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838712Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938712Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038712Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138712Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238712Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338712Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438712Smsmith * SUCH DAMAGE. 2538712Smsmith */ 26124140Sobrien 27124140Sobrien#include <sys/cdefs.h> 28124140Sobrien__FBSDID("$FreeBSD: head/sys/boot/ofw/libofw/ofw_copy.c 146368 2005-05-19 07:21:46Z grehan $"); 29124140Sobrien 3038712Smsmith/* 3138712Smsmith * MD primitives supporting placement of module data 3238712Smsmith * 3338712Smsmith * XXX should check load address/size against memory top. 3438712Smsmith */ 3538712Smsmith#include <stand.h> 3638712Smsmith 3767227Sobrien#include "libofw.h" 3838712Smsmith 3984617Sbenno#define READIN_BUF (4 * 1024) 40100318Sbenno#define PAGE_SIZE 0x1000 41100318Sbenno#define PAGE_MASK 0x0fff 4284617Sbenno 43100318Sbenno#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 44100318Sbenno 45146368Sgrehanstatic int 46146368Sgrehanofw_mapmem(vm_offset_t dest, const size_t len) 4738712Smsmith{ 48146368Sgrehan void *destp, *addr; 49146368Sgrehan size_t dlen; 50146368Sgrehan size_t resid; 51146368Sgrehan size_t nlen; 52146368Sgrehan static vm_offset_t last_dest = 0; 53146368Sgrehan static size_t last_len = 0; 54100318Sbenno 55146368Sgrehan nlen = len; 56146368Sgrehan /* 57146368Sgrehan * Check to see if this region fits in a prior mapping. 58146368Sgrehan * Allocations are generally sequential, so only check 59146368Sgrehan * the last one. 60146368Sgrehan */ 61146368Sgrehan if (dest >= last_dest && 62146368Sgrehan (dest + len) <= (last_dest + last_len)) { 63146368Sgrehan return (0); 64100318Sbenno } 65100318Sbenno 66146368Sgrehan /* 67146368Sgrehan * Trim area covered by existing mapping, if any 68146368Sgrehan */ 69146368Sgrehan if (dest < (last_dest + last_len)) { 70146368Sgrehan nlen -= (last_dest + last_len) - dest; 71146368Sgrehan dest = last_dest + last_len; 72100318Sbenno } 73100318Sbenno 74146368Sgrehan destp = (void *)(dest & ~PAGE_MASK); 75146368Sgrehan resid = dest & PAGE_MASK; 76100318Sbenno 77146368Sgrehan /* 78146368Sgrehan * To avoid repeated mappings on small allocations, 79146368Sgrehan * never map anything less than 16 pages at a time 80146368Sgrehan */ 81146368Sgrehan if ((nlen + resid) < PAGE_SIZE*8) { 82146368Sgrehan dlen = PAGE_SIZE*8; 83146368Sgrehan } else 84146368Sgrehan dlen = roundup(nlen + resid, PAGE_SIZE); 85146368Sgrehan 86146368Sgrehan if (OF_call_method("claim", memory, 3, 1, destp, dlen, 0, &addr) 87146368Sgrehan == -1) { 88146368Sgrehan printf("ofw_mapmem: physical claim failed\n"); 89146368Sgrehan return (ENOMEM); 90146368Sgrehan } 91146368Sgrehan 92146368Sgrehan if (OF_call_method("claim", mmu, 3, 1, destp, dlen, 0, &addr) == -1) { 93146368Sgrehan printf("ofw_mapmem: virtual claim failed\n"); 94146368Sgrehan return (ENOMEM); 95146368Sgrehan } 96146368Sgrehan 97146368Sgrehan if (OF_call_method("map", mmu, 4, 0, destp, destp, dlen, 0) == -1) { 98146368Sgrehan printf("ofw_mapmem: map failed\n"); 99146368Sgrehan return (ENOMEM); 100146368Sgrehan } 101146368Sgrehan 102146368Sgrehan last_dest = (vm_offset_t) destp; 103146368Sgrehan last_len = dlen; 104146368Sgrehan 105146368Sgrehan return (0); 10638712Smsmith} 10738712Smsmith 10864188Sjhbssize_t 109146368Sgrehanofw_copyin(const void *src, vm_offset_t dest, const size_t len) 110146368Sgrehan{ 111146368Sgrehan if (ofw_mapmem(dest, len)) { 112146368Sgrehan printf("ofw_copyin: map error\n"); 113146368Sgrehan return (0); 114146368Sgrehan } 115146368Sgrehan 116146368Sgrehan bcopy(src, (void *)dest, len); 117146368Sgrehan return(len); 118146368Sgrehan} 119146368Sgrehan 120146368Sgrehanssize_t 12167227Sobrienofw_copyout(const vm_offset_t src, void *dest, const size_t len) 12238764Smsmith{ 12384620Sbenno bcopy((void *)src, dest, len); 12484620Sbenno return(len); 12538764Smsmith} 12638764Smsmith 12764188Sjhbssize_t 12867227Sobrienofw_readin(const int fd, vm_offset_t dest, const size_t len) 12938712Smsmith{ 13084617Sbenno void *buf; 13184617Sbenno size_t resid, chunk, get; 13284617Sbenno ssize_t got; 13384617Sbenno vm_offset_t p; 13484617Sbenno 13584617Sbenno p = dest; 13684617Sbenno 13784617Sbenno chunk = min(READIN_BUF, len); 13884617Sbenno buf = malloc(chunk); 13984617Sbenno if (buf == NULL) { 14084617Sbenno printf("ofw_readin: buf malloc failed\n"); 14184617Sbenno return(0); 14284617Sbenno } 14384617Sbenno 144146368Sgrehan if (ofw_mapmem(dest, len)) { 145146368Sgrehan printf("ofw_readin: map error\n"); 146146368Sgrehan free(buf); 147146368Sgrehan return (0); 148146368Sgrehan } 149146368Sgrehan 15084617Sbenno for (resid = len; resid > 0; resid -= got, p += got) { 15184617Sbenno get = min(chunk, resid); 15284617Sbenno got = read(fd, buf, get); 15384617Sbenno 15484617Sbenno if (got <= 0) { 155123701Sgrehan if (got < 0) 156123701Sgrehan printf("ofw_readin: read failed\n"); 15784617Sbenno break; 15884617Sbenno } 15984617Sbenno 160146368Sgrehan bcopy(buf, (void *)p, got); 16184617Sbenno } 16284617Sbenno 16384617Sbenno free(buf); 16484617Sbenno return(len - resid); 16538712Smsmith} 166