xref: /freebsd/stand/libofw/ofw_copy.c (revision 3e15b01d)
1475008d6SBrandon Bergren /*-
2475008d6SBrandon Bergren  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3475008d6SBrandon Bergren  * All rights reserved.
4475008d6SBrandon Bergren  *
5475008d6SBrandon Bergren  * Redistribution and use in source and binary forms, with or without
6475008d6SBrandon Bergren  * modification, are permitted provided that the following conditions
7475008d6SBrandon Bergren  * are met:
8475008d6SBrandon Bergren  * 1. Redistributions of source code must retain the above copyright
9475008d6SBrandon Bergren  *    notice, this list of conditions and the following disclaimer.
10475008d6SBrandon Bergren  * 2. Redistributions in binary form must reproduce the above copyright
11475008d6SBrandon Bergren  *    notice, this list of conditions and the following disclaimer in the
12475008d6SBrandon Bergren  *    documentation and/or other materials provided with the distribution.
13475008d6SBrandon Bergren  *
14475008d6SBrandon Bergren  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15475008d6SBrandon Bergren  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16475008d6SBrandon Bergren  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17475008d6SBrandon Bergren  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18475008d6SBrandon Bergren  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19475008d6SBrandon Bergren  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20475008d6SBrandon Bergren  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21475008d6SBrandon Bergren  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22475008d6SBrandon Bergren  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23475008d6SBrandon Bergren  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24475008d6SBrandon Bergren  * SUCH DAMAGE.
25475008d6SBrandon Bergren  */
26475008d6SBrandon Bergren 
27475008d6SBrandon Bergren /*
28475008d6SBrandon Bergren  * MD primitives supporting placement of module data
29475008d6SBrandon Bergren  *
30475008d6SBrandon Bergren  * XXX should check load address/size against memory top.
31475008d6SBrandon Bergren  */
32475008d6SBrandon Bergren #include <stand.h>
33475008d6SBrandon Bergren 
34475008d6SBrandon Bergren #include "libofw.h"
35475008d6SBrandon Bergren 
36475008d6SBrandon Bergren #define	READIN_BUF	(4 * 1024)
37475008d6SBrandon Bergren #define	PAGE_SIZE	0x1000
38475008d6SBrandon Bergren #define	PAGE_MASK	0x0fff
39475008d6SBrandon Bergren #define	MAPMEM_PAGE_INC 128 /* Half-MB at a time */
40475008d6SBrandon Bergren 
41475008d6SBrandon Bergren 
42475008d6SBrandon Bergren #define	roundup(x, y)	((((x)+((y)-1))/(y))*(y))
43475008d6SBrandon Bergren 
44475008d6SBrandon Bergren static int
ofw_mapmem(vm_offset_t dest,const size_t len)45475008d6SBrandon Bergren ofw_mapmem(vm_offset_t dest, const size_t len)
46475008d6SBrandon Bergren {
47475008d6SBrandon Bergren         void    *destp, *addr;
48475008d6SBrandon Bergren         size_t  dlen;
49475008d6SBrandon Bergren         size_t  resid;
50475008d6SBrandon Bergren 	size_t  nlen;
51475008d6SBrandon Bergren         static vm_offset_t last_dest = 0;
52475008d6SBrandon Bergren         static size_t last_len = 0;
53475008d6SBrandon Bergren 
54475008d6SBrandon Bergren 	nlen = len;
55475008d6SBrandon Bergren         /*
56475008d6SBrandon Bergren          * Check to see if this region fits in a prior mapping.
57475008d6SBrandon Bergren          * Allocations are generally sequential, so only check
58475008d6SBrandon Bergren          * the last one.
59475008d6SBrandon Bergren          */
60475008d6SBrandon Bergren         if (dest >= last_dest &&
61475008d6SBrandon Bergren             (dest + len) <= (last_dest + last_len)) {
62475008d6SBrandon Bergren                 return (0);
63475008d6SBrandon Bergren 	}
64475008d6SBrandon Bergren 
65475008d6SBrandon Bergren 	/*
66475008d6SBrandon Bergren 	 * Trim area covered by existing mapping, if any
67475008d6SBrandon Bergren 	 */
68475008d6SBrandon Bergren 	if (dest < (last_dest + last_len) && dest >= last_dest) {
69475008d6SBrandon Bergren 		nlen -= (last_dest + last_len) - dest;
70475008d6SBrandon Bergren 		dest = last_dest + last_len;
71475008d6SBrandon Bergren 	}
72475008d6SBrandon Bergren 
73475008d6SBrandon Bergren         destp = (void *)(dest & ~PAGE_MASK);
74475008d6SBrandon Bergren         resid = dest & PAGE_MASK;
75475008d6SBrandon Bergren 
76475008d6SBrandon Bergren 	/*
77475008d6SBrandon Bergren 	 * To avoid repeated mappings on small allocations,
78475008d6SBrandon Bergren 	 * never map anything less than MAPMEM_PAGE_INC pages at a time
79475008d6SBrandon Bergren 	 */
80475008d6SBrandon Bergren 	if ((nlen + resid) < PAGE_SIZE*MAPMEM_PAGE_INC) {
81475008d6SBrandon Bergren 		dlen = PAGE_SIZE*MAPMEM_PAGE_INC;
82475008d6SBrandon Bergren 	} else
83475008d6SBrandon Bergren 		dlen = roundup(nlen + resid, PAGE_SIZE);
84475008d6SBrandon Bergren 
85475008d6SBrandon Bergren         if (OF_call_method("claim", memory, 3, 1, destp, dlen, 0, &addr)
86475008d6SBrandon Bergren             == -1) {
87475008d6SBrandon Bergren                 printf("ofw_mapmem: physical claim failed\n");
88475008d6SBrandon Bergren                 return (ENOMEM);
89475008d6SBrandon Bergren         }
90475008d6SBrandon Bergren 
91475008d6SBrandon Bergren 	/*
92475008d6SBrandon Bergren 	 * We only do virtual memory management when real_mode is false.
93475008d6SBrandon Bergren 	 */
94475008d6SBrandon Bergren 	if (real_mode == 0) {
95475008d6SBrandon Bergren 		if (OF_call_method("claim", mmu, 3, 1, destp, dlen, 0, &addr)
96475008d6SBrandon Bergren 		    == -1) {
97475008d6SBrandon Bergren 			printf("ofw_mapmem: virtual claim failed\n");
98475008d6SBrandon Bergren 			return (ENOMEM);
99475008d6SBrandon Bergren 		}
100475008d6SBrandon Bergren 
101475008d6SBrandon Bergren 		if (OF_call_method("map", mmu, 4, 0, destp, destp, dlen, 0)
102475008d6SBrandon Bergren 		    == -1) {
103475008d6SBrandon Bergren 			printf("ofw_mapmem: map failed\n");
104475008d6SBrandon Bergren 			return (ENOMEM);
105475008d6SBrandon Bergren 		}
106475008d6SBrandon Bergren 	}
107475008d6SBrandon Bergren         last_dest = (vm_offset_t) destp;
108475008d6SBrandon Bergren         last_len  = dlen;
109475008d6SBrandon Bergren 
110475008d6SBrandon Bergren         return (0);
111475008d6SBrandon Bergren }
112475008d6SBrandon Bergren 
113475008d6SBrandon Bergren ssize_t
ofw_copyin(const void * src,vm_offset_t dest,const size_t len)114475008d6SBrandon Bergren ofw_copyin(const void *src, vm_offset_t dest, const size_t len)
115475008d6SBrandon Bergren {
116475008d6SBrandon Bergren         if (ofw_mapmem(dest, len)) {
117475008d6SBrandon Bergren                 printf("ofw_copyin: map error\n");
118475008d6SBrandon Bergren                 return (0);
119475008d6SBrandon Bergren         }
120475008d6SBrandon Bergren 
121475008d6SBrandon Bergren         bcopy(src, (void *)dest, len);
122475008d6SBrandon Bergren         return(len);
123475008d6SBrandon Bergren }
124475008d6SBrandon Bergren 
125475008d6SBrandon Bergren ssize_t
ofw_copyout(const vm_offset_t src,void * dest,const size_t len)126475008d6SBrandon Bergren ofw_copyout(const vm_offset_t src, void *dest, const size_t len)
127475008d6SBrandon Bergren {
128475008d6SBrandon Bergren 	bcopy((void *)src, dest, len);
129475008d6SBrandon Bergren 	return(len);
130475008d6SBrandon Bergren }
131475008d6SBrandon Bergren 
132475008d6SBrandon Bergren ssize_t
ofw_readin(readin_handle_t fd,vm_offset_t dest,const size_t len)133afc571b1SSimon J. Gerraty ofw_readin(readin_handle_t fd, vm_offset_t dest, const size_t len)
134475008d6SBrandon Bergren {
135475008d6SBrandon Bergren 	void		*buf;
136475008d6SBrandon Bergren 	size_t		resid, chunk, get;
137475008d6SBrandon Bergren 	ssize_t		got;
138475008d6SBrandon Bergren 	vm_offset_t	p;
139475008d6SBrandon Bergren 
140475008d6SBrandon Bergren 	p = dest;
141475008d6SBrandon Bergren 
142475008d6SBrandon Bergren 	chunk = min(READIN_BUF, len);
143475008d6SBrandon Bergren 	buf = malloc(chunk);
144475008d6SBrandon Bergren 	if (buf == NULL) {
145475008d6SBrandon Bergren 		printf("ofw_readin: buf malloc failed\n");
146475008d6SBrandon Bergren 		return(0);
147475008d6SBrandon Bergren 	}
148475008d6SBrandon Bergren 
149475008d6SBrandon Bergren         if (ofw_mapmem(dest, len)) {
150475008d6SBrandon Bergren                 printf("ofw_readin: map error\n");
151475008d6SBrandon Bergren                 free(buf);
152475008d6SBrandon Bergren                 return (0);
153475008d6SBrandon Bergren         }
154475008d6SBrandon Bergren 
155475008d6SBrandon Bergren 	for (resid = len; resid > 0; resid -= got, p += got) {
156475008d6SBrandon Bergren 		get = min(chunk, resid);
157afc571b1SSimon J. Gerraty 		got = VECTX_READ(fd, buf, get);
158475008d6SBrandon Bergren 
159475008d6SBrandon Bergren 		if (got <= 0) {
160475008d6SBrandon Bergren 			if (got < 0)
161475008d6SBrandon Bergren 				printf("ofw_readin: read failed\n");
162475008d6SBrandon Bergren 			break;
163475008d6SBrandon Bergren 		}
164475008d6SBrandon Bergren 
165475008d6SBrandon Bergren 		bcopy(buf, (void *)p, got);
166475008d6SBrandon Bergren 	}
167475008d6SBrandon Bergren 
168475008d6SBrandon Bergren 	free(buf);
169475008d6SBrandon Bergren 	return(len - resid);
170475008d6SBrandon Bergren }
171