Some clean up work with faults.
[gem5.git] / arch / alpha / vtophys.cc
1 /*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
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 are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <string>
30
31 #include "arch/alpha/vtophys.hh"
32 #include "base/trace.hh"
33 #include "cpu/exec_context.hh"
34 #include "mem/functional/physical.hh"
35
36 using namespace std;
37 using namespace AlphaISA;
38
39 AlphaISA::PageTableEntry
40 kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, AlphaISA::VAddr vaddr)
41 {
42 Addr level1_pte = ptbr + vaddr.level1();
43 AlphaISA::PageTableEntry level1 = pmem->phys_read_qword(level1_pte);
44 if (!level1.valid()) {
45 DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr);
46 return 0;
47 }
48
49 Addr level2_pte = level1.paddr() + vaddr.level2();
50 AlphaISA::PageTableEntry level2 = pmem->phys_read_qword(level2_pte);
51 if (!level2.valid()) {
52 DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr);
53 return 0;
54 }
55
56 Addr level3_pte = level2.paddr() + vaddr.level3();
57 AlphaISA::PageTableEntry level3 = pmem->phys_read_qword(level3_pte);
58 if (!level3.valid()) {
59 DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr);
60 return 0;
61 }
62 return level3;
63 }
64
65 Addr
66 vtophys(PhysicalMemory *xc, Addr vaddr)
67 {
68 Addr paddr = 0;
69 if (AlphaISA::IsUSeg(vaddr))
70 DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr);
71 else if (AlphaISA::IsK0Seg(vaddr))
72 paddr = AlphaISA::K0Seg2Phys(vaddr);
73 else
74 panic("vtophys: ptbr is not set on virtual lookup");
75
76 DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
77
78 return paddr;
79 }
80
81 Addr
82 vtophys(ExecContext *xc, Addr addr)
83 {
84 AlphaISA::VAddr vaddr = addr;
85 Addr ptbr = xc->readMiscReg(AlphaISA::IPR_PALtemp20);
86 Addr paddr = 0;
87 //@todo Andrew couldn't remember why he commented some of this code
88 //so I put it back in. Perhaps something to do with gdb debugging?
89 if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) {
90 paddr = vaddr & ~ULL(1);
91 } else {
92 if (AlphaISA::IsK0Seg(vaddr)) {
93 paddr = AlphaISA::K0Seg2Phys(vaddr);
94 } else if (!ptbr) {
95 paddr = vaddr;
96 } else {
97 AlphaISA::PageTableEntry pte =
98 kernel_pte_lookup(xc->physmem, ptbr, vaddr);
99 if (pte.valid())
100 paddr = pte.paddr() | vaddr.offset();
101 }
102 }
103
104
105 DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
106
107 return paddr;
108 }
109
110 uint8_t *
111 ptomem(ExecContext *xc, Addr paddr, size_t len)
112 {
113 return xc->physmem->dma_addr(paddr, len);
114 }
115
116 uint8_t *
117 vtomem(ExecContext *xc, Addr vaddr, size_t len)
118 {
119 Addr paddr = vtophys(xc, vaddr);
120 return xc->physmem->dma_addr(paddr, len);
121 }
122
123 void
124 CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen)
125 {
126 Addr paddr;
127 char *dmaaddr;
128 char *dst = (char *)dest;
129 int len;
130
131 paddr = vtophys(xc, src);
132 len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)),
133 (int)cplen);
134 dmaaddr = (char *)xc->physmem->dma_addr(paddr, len);
135 assert(dmaaddr);
136
137 memcpy(dst, dmaaddr, len);
138 if (len == cplen)
139 return;
140
141 cplen -= len;
142 dst += len;
143 src += len;
144
145 while (cplen > AlphaISA::PageBytes) {
146 paddr = vtophys(xc, src);
147 dmaaddr = (char *)xc->physmem->dma_addr(paddr, AlphaISA::PageBytes);
148 assert(dmaaddr);
149
150 memcpy(dst, dmaaddr, AlphaISA::PageBytes);
151 cplen -= AlphaISA::PageBytes;
152 dst += AlphaISA::PageBytes;
153 src += AlphaISA::PageBytes;
154 }
155
156 if (cplen > 0) {
157 paddr = vtophys(xc, src);
158 dmaaddr = (char *)xc->physmem->dma_addr(paddr, cplen);
159 assert(dmaaddr);
160
161 memcpy(dst, dmaaddr, cplen);
162 }
163 }
164
165 void
166 CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen)
167 {
168 Addr paddr;
169 char *dmaaddr;
170 char *src = (char *)source;
171 int len;
172
173 paddr = vtophys(xc, dest);
174 len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)),
175 (int)cplen);
176 dmaaddr = (char *)xc->physmem->dma_addr(paddr, len);
177 assert(dmaaddr);
178
179 memcpy(dmaaddr, src, len);
180 if (len == cplen)
181 return;
182
183 cplen -= len;
184 src += len;
185 dest += len;
186
187 while (cplen > AlphaISA::PageBytes) {
188 paddr = vtophys(xc, dest);
189 dmaaddr = (char *)xc->physmem->dma_addr(paddr, AlphaISA::PageBytes);
190 assert(dmaaddr);
191
192 memcpy(dmaaddr, src, AlphaISA::PageBytes);
193 cplen -= AlphaISA::PageBytes;
194 src += AlphaISA::PageBytes;
195 dest += AlphaISA::PageBytes;
196 }
197
198 if (cplen > 0) {
199 paddr = vtophys(xc, dest);
200 dmaaddr = (char *)xc->physmem->dma_addr(paddr, cplen);
201 assert(dmaaddr);
202
203 memcpy(dmaaddr, src, cplen);
204 }
205 }
206
207 void
208 CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen)
209 {
210 Addr paddr;
211 char *dmaaddr;
212 int len;
213
214 paddr = vtophys(xc, vaddr);
215 len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)),
216 (int)maxlen);
217 dmaaddr = (char *)xc->physmem->dma_addr(paddr, len);
218 assert(dmaaddr);
219
220 char *term = (char *)memchr(dmaaddr, 0, len);
221 if (term)
222 len = term - dmaaddr + 1;
223
224 memcpy(dst, dmaaddr, len);
225
226 if (term || len == maxlen)
227 return;
228
229 maxlen -= len;
230 dst += len;
231 vaddr += len;
232
233 while (maxlen > AlphaISA::PageBytes) {
234 paddr = vtophys(xc, vaddr);
235 dmaaddr = (char *)xc->physmem->dma_addr(paddr, AlphaISA::PageBytes);
236 assert(dmaaddr);
237
238 char *term = (char *)memchr(dmaaddr, 0, AlphaISA::PageBytes);
239 len = term ? (term - dmaaddr + 1) : AlphaISA::PageBytes;
240
241 memcpy(dst, dmaaddr, len);
242 if (term)
243 return;
244
245 maxlen -= AlphaISA::PageBytes;
246 dst += AlphaISA::PageBytes;
247 vaddr += AlphaISA::PageBytes;
248 }
249
250 if (maxlen > 0) {
251 paddr = vtophys(xc, vaddr);
252 dmaaddr = (char *)xc->physmem->dma_addr(paddr, maxlen);
253 assert(dmaaddr);
254
255 char *term = (char *)memchr(dmaaddr, 0, maxlen);
256 len = term ? (term - dmaaddr + 1) : maxlen;
257
258 memcpy(dst, dmaaddr, len);
259
260 maxlen -= len;
261 }
262
263 if (maxlen == 0)
264 dst[maxlen] = '\0';
265 }