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