ofw_copy.c revision 212165
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 212165 2010-09-02 22:26:49Z nwhitehorn $"); 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 42148319Sgrehan#define MAPMEM_PAGE_INC 16 4384617Sbenno 44148319Sgrehan 45100318Sbenno#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 46100318Sbenno 47146368Sgrehanstatic int 48146368Sgrehanofw_mapmem(vm_offset_t dest, const size_t len) 4938712Smsmith{ 50146368Sgrehan void *destp, *addr; 51146368Sgrehan size_t dlen; 52146368Sgrehan size_t resid; 53146368Sgrehan size_t nlen; 54146368Sgrehan static vm_offset_t last_dest = 0; 55146368Sgrehan static size_t last_len = 0; 56100318Sbenno 57146368Sgrehan nlen = len; 58146368Sgrehan /* 59146368Sgrehan * Check to see if this region fits in a prior mapping. 60146368Sgrehan * Allocations are generally sequential, so only check 61146368Sgrehan * the last one. 62146368Sgrehan */ 63146368Sgrehan if (dest >= last_dest && 64146368Sgrehan (dest + len) <= (last_dest + last_len)) { 65146368Sgrehan return (0); 66100318Sbenno } 67100318Sbenno 68146368Sgrehan /* 69146368Sgrehan * Trim area covered by existing mapping, if any 70146368Sgrehan */ 71212165Snwhitehorn if (dest < (last_dest + last_len) && dest >= last_dest) { 72146368Sgrehan nlen -= (last_dest + last_len) - dest; 73146368Sgrehan dest = last_dest + last_len; 74100318Sbenno } 75100318Sbenno 76146368Sgrehan destp = (void *)(dest & ~PAGE_MASK); 77146368Sgrehan resid = dest & PAGE_MASK; 78100318Sbenno 79146368Sgrehan /* 80146368Sgrehan * To avoid repeated mappings on small allocations, 81148319Sgrehan * never map anything less than MAPMEM_PAGE_INC pages at a time 82146368Sgrehan */ 83148319Sgrehan if ((nlen + resid) < PAGE_SIZE*MAPMEM_PAGE_INC) { 84148319Sgrehan dlen = PAGE_SIZE*MAPMEM_PAGE_INC; 85146368Sgrehan } else 86146368Sgrehan dlen = roundup(nlen + resid, PAGE_SIZE); 87146368Sgrehan 88146368Sgrehan if (OF_call_method("claim", memory, 3, 1, destp, dlen, 0, &addr) 89146368Sgrehan == -1) { 90146368Sgrehan printf("ofw_mapmem: physical claim failed\n"); 91146368Sgrehan return (ENOMEM); 92146368Sgrehan } 93146368Sgrehan 94146368Sgrehan if (OF_call_method("claim", mmu, 3, 1, destp, dlen, 0, &addr) == -1) { 95146368Sgrehan printf("ofw_mapmem: virtual claim failed\n"); 96146368Sgrehan return (ENOMEM); 97146368Sgrehan } 98146368Sgrehan 99146368Sgrehan if (OF_call_method("map", mmu, 4, 0, destp, destp, dlen, 0) == -1) { 100146368Sgrehan printf("ofw_mapmem: map failed\n"); 101146368Sgrehan return (ENOMEM); 102146368Sgrehan } 103146368Sgrehan 104146368Sgrehan last_dest = (vm_offset_t) destp; 105146368Sgrehan last_len = dlen; 106146368Sgrehan 107146368Sgrehan return (0); 10838712Smsmith} 10938712Smsmith 11064188Sjhbssize_t 111146368Sgrehanofw_copyin(const void *src, vm_offset_t dest, const size_t len) 112146368Sgrehan{ 113146368Sgrehan if (ofw_mapmem(dest, len)) { 114146368Sgrehan printf("ofw_copyin: map error\n"); 115146368Sgrehan return (0); 116146368Sgrehan } 117146368Sgrehan 118146368Sgrehan bcopy(src, (void *)dest, len); 119146368Sgrehan return(len); 120146368Sgrehan} 121146368Sgrehan 122146368Sgrehanssize_t 12367227Sobrienofw_copyout(const vm_offset_t src, void *dest, const size_t len) 12438764Smsmith{ 12584620Sbenno bcopy((void *)src, dest, len); 12684620Sbenno return(len); 12738764Smsmith} 12838764Smsmith 12964188Sjhbssize_t 13067227Sobrienofw_readin(const int fd, vm_offset_t dest, const size_t len) 13138712Smsmith{ 13284617Sbenno void *buf; 13384617Sbenno size_t resid, chunk, get; 13484617Sbenno ssize_t got; 13584617Sbenno vm_offset_t p; 13684617Sbenno 13784617Sbenno p = dest; 13884617Sbenno 13984617Sbenno chunk = min(READIN_BUF, len); 14084617Sbenno buf = malloc(chunk); 14184617Sbenno if (buf == NULL) { 14284617Sbenno printf("ofw_readin: buf malloc failed\n"); 14384617Sbenno return(0); 14484617Sbenno } 14584617Sbenno 146146368Sgrehan if (ofw_mapmem(dest, len)) { 147146368Sgrehan printf("ofw_readin: map error\n"); 148146368Sgrehan free(buf); 149146368Sgrehan return (0); 150146368Sgrehan } 151146368Sgrehan 15284617Sbenno for (resid = len; resid > 0; resid -= got, p += got) { 15384617Sbenno get = min(chunk, resid); 15484617Sbenno got = read(fd, buf, get); 15584617Sbenno 15684617Sbenno if (got <= 0) { 157123701Sgrehan if (got < 0) 158123701Sgrehan printf("ofw_readin: read failed\n"); 15984617Sbenno break; 16084617Sbenno } 16184617Sbenno 162146368Sgrehan bcopy(buf, (void *)p, got); 16384617Sbenno } 16484617Sbenno 16584617Sbenno free(buf); 16684617Sbenno return(len - resid); 16738712Smsmith} 168