copy.c revision 220313
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 220313 2011-04-03 23:49:20Z marcel $");
29
30#include <stand.h>
31#include <machine/param.h>
32
33#include "libia64.h"
34
35u_int ia64_legacy_kernel;
36
37uint64_t *ia64_pgtbl;
38uint32_t ia64_pgtblsz;
39
40static int
41pgtbl_extend(u_int idx)
42{
43	uint64_t *pgtbl;
44	uint32_t pgtblsz;
45	u_int pot;
46
47	pgtblsz = (idx + 1) << 3;
48
49	/* The minimum size is 4KB. */
50	if (pgtblsz < 4096)
51		pgtblsz = 4096;
52
53	/* Find the next higher power of 2. */
54	pgtblsz--;
55	for (pot = 1; pot < 32; pot <<= 1)
56		pgtblsz = pgtblsz | (pgtblsz >> pot);
57	pgtblsz++;
58
59	/* The maximum size is 1MB. */
60	if (pgtblsz > 1048576)
61		return (ENOMEM);
62
63	/* Make sure the size is a valid (mappable) page size. */
64	if (pgtblsz == 32*1024 || pgtblsz == 128*1024 || pgtblsz == 512*1024)
65		pgtblsz <<= 1;
66
67	/* Allocate naturally aligned memory. */
68	pgtbl = (void *)ia64_platform_alloc(0, pgtblsz);
69	if (pgtbl == NULL)
70		return (ENOMEM);
71
72	/* Initialize new page table. */
73	if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl)
74		bcopy(ia64_pgtbl, pgtbl, ia64_pgtblsz);
75	bzero(pgtbl + (ia64_pgtblsz >> 3), pgtblsz - ia64_pgtblsz);
76
77	if (ia64_pgtbl != NULL && ia64_pgtbl != pgtbl)
78		ia64_platform_free(0, (uintptr_t)ia64_pgtbl, ia64_pgtblsz);
79
80	ia64_pgtbl = pgtbl;
81	ia64_pgtblsz = pgtblsz;
82	return (0);
83}
84
85void *
86ia64_va2pa(vm_offset_t va, size_t *len)
87{
88	uint64_t pa;
89	u_int idx, ofs;
90	int error;
91
92	/* Backward compatibility. */
93	if (va >= IA64_RR_BASE(7)) {
94		ia64_legacy_kernel = 1;
95		pa = IA64_RR_MASK(va);
96		return ((void *)pa);
97	}
98
99	if (va < IA64_PBVM_BASE) {
100		error = EINVAL;
101		goto fail;
102	}
103
104	ia64_legacy_kernel = 0;
105
106	idx = (va - IA64_PBVM_BASE) >> IA64_PBVM_PAGE_SHIFT;
107	if (idx >= (ia64_pgtblsz >> 3)) {
108		error = pgtbl_extend(idx);
109		if (error)
110			goto fail;
111	}
112
113	ofs = va & IA64_PBVM_PAGE_MASK;
114	pa = ia64_pgtbl[idx];
115	if (pa == 0) {
116		pa = ia64_platform_alloc(va - ofs, IA64_PBVM_PAGE_SIZE);
117		if (pa == 0) {
118			error = ENOMEM;
119			goto fail;
120		}
121		ia64_pgtbl[idx] = pa;
122	}
123	pa += ofs;
124
125	/* We can not cross page boundaries (in general). */
126	if (*len + ofs > IA64_PBVM_PAGE_SIZE)
127		*len = IA64_PBVM_PAGE_SIZE - ofs;
128
129	return ((void *)pa);
130
131 fail:
132	*len = 0;
133	return (NULL);
134}
135
136ssize_t
137ia64_copyin(const void *src, vm_offset_t va, size_t len)
138{
139	void *pa;
140	ssize_t res;
141	size_t sz;
142
143	res = 0;
144	while (len > 0) {
145		sz = len;
146		pa = ia64_va2pa(va, &sz);
147		if (sz == 0)
148			break;
149		bcopy(src, pa, sz);
150		len -= sz;
151		res += sz;
152		va += sz;
153	}
154	return (res);
155}
156
157ssize_t
158ia64_copyout(vm_offset_t va, void *dst, size_t len)
159{
160	void *pa;
161	ssize_t res;
162	size_t sz;
163
164	res = 0;
165	while (len > 0) {
166		sz = len;
167		pa = ia64_va2pa(va, &sz);
168		if (sz == 0)
169			break;
170		bcopy(pa, dst, sz);
171		len -= sz;
172		res += sz;
173		va += sz;
174	}
175	return (res);
176}
177
178uint64_t
179ia64_loadaddr(u_int type, void *data, uint64_t addr)
180{
181	uint64_t align;
182
183	/*
184	 * Align ELF objects at PBVM page boundaries.  Align all other
185	 * objects at cache line boundaries for good measure.
186	 */
187	align = (type == LOAD_ELF) ? IA64_PBVM_PAGE_SIZE : CACHE_LINE_SIZE;
188	return ((addr + align - 1) & ~(align - 1));
189}
190
191ssize_t
192ia64_readin(int fd, vm_offset_t va, size_t len)
193{
194	void *pa;
195	ssize_t res, s;
196	size_t sz;
197
198	res = 0;
199	while (len > 0) {
200		sz = len;
201		pa = ia64_va2pa(va, &sz);
202		if (sz == 0)
203			break;
204		s = read(fd, pa, sz);
205		if (s <= 0)
206			break;
207		len -= s;
208		res += s;
209		va += s;
210	}
211	return (res);
212}
213