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: stable/11/stand/ofw/libofw/ofw_copy.c 329183 2018-02-12 20:51:28Z kevans $"); 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 42329183Skevans#define MAPMEM_PAGE_INC 128 /* Half-MB at a time */ 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 94215438Sandreast /* 95215438Sandreast * We only do virtual memory management when real_mode is false. 96215438Sandreast */ 97215438Sandreast if (real_mode == 0) { 98215438Sandreast if (OF_call_method("claim", mmu, 3, 1, destp, dlen, 0, &addr) 99215438Sandreast == -1) { 100215438Sandreast printf("ofw_mapmem: virtual claim failed\n"); 101215438Sandreast return (ENOMEM); 102215438Sandreast } 103146368Sgrehan 104215438Sandreast if (OF_call_method("map", mmu, 4, 0, destp, destp, dlen, 0) 105215438Sandreast == -1) { 106215438Sandreast printf("ofw_mapmem: map failed\n"); 107215438Sandreast return (ENOMEM); 108215438Sandreast } 109215438Sandreast } 110146368Sgrehan last_dest = (vm_offset_t) destp; 111146368Sgrehan last_len = dlen; 112146368Sgrehan 113146368Sgrehan return (0); 11438712Smsmith} 11538712Smsmith 11664188Sjhbssize_t 117146368Sgrehanofw_copyin(const void *src, vm_offset_t dest, const size_t len) 118146368Sgrehan{ 119146368Sgrehan if (ofw_mapmem(dest, len)) { 120146368Sgrehan printf("ofw_copyin: map error\n"); 121146368Sgrehan return (0); 122146368Sgrehan } 123146368Sgrehan 124146368Sgrehan bcopy(src, (void *)dest, len); 125146368Sgrehan return(len); 126146368Sgrehan} 127146368Sgrehan 128146368Sgrehanssize_t 12967227Sobrienofw_copyout(const vm_offset_t src, void *dest, const size_t len) 13038764Smsmith{ 13184620Sbenno bcopy((void *)src, dest, len); 13284620Sbenno return(len); 13338764Smsmith} 13438764Smsmith 13564188Sjhbssize_t 13667227Sobrienofw_readin(const int fd, vm_offset_t dest, const size_t len) 13738712Smsmith{ 13884617Sbenno void *buf; 13984617Sbenno size_t resid, chunk, get; 14084617Sbenno ssize_t got; 14184617Sbenno vm_offset_t p; 14284617Sbenno 14384617Sbenno p = dest; 14484617Sbenno 14584617Sbenno chunk = min(READIN_BUF, len); 14684617Sbenno buf = malloc(chunk); 14784617Sbenno if (buf == NULL) { 14884617Sbenno printf("ofw_readin: buf malloc failed\n"); 14984617Sbenno return(0); 15084617Sbenno } 15184617Sbenno 152146368Sgrehan if (ofw_mapmem(dest, len)) { 153146368Sgrehan printf("ofw_readin: map error\n"); 154146368Sgrehan free(buf); 155146368Sgrehan return (0); 156146368Sgrehan } 157146368Sgrehan 15884617Sbenno for (resid = len; resid > 0; resid -= got, p += got) { 15984617Sbenno get = min(chunk, resid); 16084617Sbenno got = read(fd, buf, get); 16184617Sbenno 16284617Sbenno if (got <= 0) { 163123701Sgrehan if (got < 0) 164123701Sgrehan printf("ofw_readin: read failed\n"); 16584617Sbenno break; 16684617Sbenno } 16784617Sbenno 168146368Sgrehan bcopy(buf, (void *)p, got); 16984617Sbenno } 17084617Sbenno 17184617Sbenno free(buf); 17284617Sbenno return(len - resid); 17338712Smsmith} 174