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: stable/11/stand/ofw/libofw/ofw_copy.c 329183 2018-02-12 20:51:28Z kevans $");
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
47static int
48ofw_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
116ssize_t
117ofw_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
128ssize_t
129ofw_copyout(const vm_offset_t src, void *dest, const size_t len)
130{
131	bcopy((void *)src, dest, len);
132	return(len);
133}
134
135ssize_t
136ofw_readin(const int 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 = 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