copy.c revision 219691
1/*-
2 * Copyright (c) 2006 Marcel Moolenaar
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 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/boot/ia64/common/copy.c 219691 2011-03-16 03:53:18Z marcel $");
29
30#include <stand.h>
31#include <ia64/include/vmparam.h>
32
33#include "libia64.h"
34
35uint64_t *ia64_pgtbl;
36uint32_t ia64_pgtblsz;
37
38static int
39pgtbl_extend(u_int idx)
40{
41	uint64_t *pgtbl;
42	uint32_t pgtblsz;
43	u_int pot;
44
45	pgtblsz = (idx + 1) << 3;
46
47	/* The minimum size is 4KB. */
48	if (pgtblsz < 4096)
49		pgtblsz = 4096;
50
51	/* Find the next higher power of 2. */
52	pgtblsz--;
53	for (pot = 1; pot < 32; pot <<= 1)
54		pgtblsz = pgtblsz | (pgtblsz >> pot);
55	pgtblsz++;
56
57	/* The maximum size is 1MB. */
58	if (pgtblsz > 1048576)
59		return (ENOMEM);
60
61	/* Make sure the size is a valid (mappable) page size. */
62	if (pgtblsz == 32*1024 || pgtblsz == 128*1024 || pgtblsz == 512*1024)
63		pgtblsz <<= 1;
64
65	/* Allocate naturally aligned memory. */
66	pgtbl = (void *)ia64_platform_alloc(0, pgtblsz);
67	if (pgtbl == NULL)
68		return (ENOMEM);
69
70	/* Initialize new page table. */
71	if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl)
72		bcopy(ia64_pgtbl, pgtbl, ia64_pgtblsz);
73	bzero(pgtbl + (ia64_pgtblsz >> 3), pgtblsz - ia64_pgtblsz);
74
75	if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl)
76		ia64_platform_free(0, (uintptr_t)ia64_pgtbl, ia64_pgtblsz);
77
78	ia64_pgtbl = pgtbl;
79	ia64_pgtblsz = pgtblsz;
80	return (0);
81}
82
83static void *
84va2pa(vm_offset_t va, size_t *len)
85{
86	uint64_t pa;
87	u_int idx, ofs;
88	int error;
89
90	/* Backward compatibility. */
91	if (va >= IA64_RR_BASE(7)) {
92		pa = IA64_RR_MASK(va);
93		return ((void *)pa);
94	}
95
96	if (va < IA64_PBVM_BASE) {
97		error = EINVAL;
98		goto fail;
99	}
100
101	idx = (va - IA64_PBVM_BASE) >> IA64_PBVM_PAGE_SHIFT;
102	if (idx >= (ia64_pgtblsz >> 3)) {
103		error = pgtbl_extend(idx);
104		if (error)
105			goto fail;
106	}
107
108	ofs = va & IA64_PBVM_PAGE_MASK;
109	pa = ia64_pgtbl[idx];
110	if (pa == 0) {
111		pa = ia64_platform_alloc(va - ofs, IA64_PBVM_PAGE_SIZE);
112		if (pa == 0) {
113			error = ENOMEM;
114			goto fail;
115		}
116		ia64_pgtbl[idx] = pa;
117	}
118	pa += ofs;
119
120	/* We can not cross page boundaries (in general). */
121	if (*len + ofs > IA64_PBVM_PAGE_SIZE)
122		*len = IA64_PBVM_PAGE_SIZE - ofs;
123
124	return ((void *)pa);
125
126 fail:
127	*len = 0;
128	return (NULL);
129}
130
131ssize_t
132ia64_copyin(const void *src, vm_offset_t va, size_t len)
133{
134	void *pa;
135	ssize_t res;
136	size_t sz;
137
138	res = 0;
139	while (len > 0) {
140		sz = len;
141		pa = va2pa(va, &sz);
142		if (sz == 0)
143			break;
144		bcopy(src, pa, sz);
145		len -= sz;
146		res += sz;
147		va += sz;
148	}
149	return (res);
150}
151
152ssize_t
153ia64_copyout(vm_offset_t va, void *dst, size_t len)
154{
155	void *pa;
156	ssize_t res;
157	size_t sz;
158
159	res = 0;
160	while (len > 0) {
161		sz = len;
162		pa = va2pa(va, &sz);
163		if (sz == 0)
164			break;
165		bcopy(pa, dst, sz);
166		len -= sz;
167		res += sz;
168		va += sz;
169	}
170	return (res);
171}
172
173ssize_t
174ia64_readin(int fd, vm_offset_t va, size_t len)
175{
176	void *pa;
177	ssize_t res, s;
178	size_t sz;
179
180	res = 0;
181	while (len > 0) {
182		sz = len;
183		pa = va2pa(va, &sz);
184		if (sz == 0)
185			break;
186		s = read(fd, pa, sz);
187		if (s <= 0)
188			break;
189		len -= s;
190		res += s;
191		va += s;
192	}
193	return (res);
194}
195