Merge ktlim@zizzer:/bk/m5
[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->getPhysMemPtr(), 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->getPhysMemPtr()->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->getPhysMemPtr()->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->getPhysMemPtr()->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->getPhysMemPtr()->dma_addr(paddr,
148 AlphaISA::PageBytes);
149 assert(dmaaddr);
150
151 memcpy(dst, dmaaddr, AlphaISA::PageBytes);
152 cplen -= AlphaISA::PageBytes;
153 dst += AlphaISA::PageBytes;
154 src += AlphaISA::PageBytes;
155 }
156
157 if (cplen > 0) {
158 paddr = vtophys(xc, src);
159 dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, cplen);
160 assert(dmaaddr);
161
162 memcpy(dst, dmaaddr, cplen);
163 }
164 }
165
166 void
167 CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen)
168 {
169 Addr paddr;
170 char *dmaaddr;
171 char *src = (char *)source;
172 int len;
173
174 paddr = vtophys(xc, dest);
175 len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)),
176 (int)cplen);
177 dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, len);
178 assert(dmaaddr);
179
180 memcpy(dmaaddr, src, len);
181 if (len == cplen)
182 return;
183
184 cplen -= len;
185 src += len;
186 dest += len;
187
188 while (cplen > AlphaISA::PageBytes) {
189 paddr = vtophys(xc, dest);
190 dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr,
191 AlphaISA::PageBytes);
192 assert(dmaaddr);
193
194 memcpy(dmaaddr, src, AlphaISA::PageBytes);
195 cplen -= AlphaISA::PageBytes;
196 src += AlphaISA::PageBytes;
197 dest += AlphaISA::PageBytes;
198 }
199
200 if (cplen > 0) {
201 paddr = vtophys(xc, dest);
202 dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, cplen);
203 assert(dmaaddr);
204
205 memcpy(dmaaddr, src, cplen);
206 }
207 }
208
209 void
210 CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen)
211 {
212 Addr paddr;
213 char *dmaaddr;
214 int len;
215
216 paddr = vtophys(xc, vaddr);
217 len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)),
218 (int)maxlen);
219 dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, len);
220 assert(dmaaddr);
221
222 char *term = (char *)memchr(dmaaddr, 0, len);
223 if (term)
224 len = term - dmaaddr + 1;
225
226 memcpy(dst, dmaaddr, len);
227
228 if (term || len == maxlen)
229 return;
230
231 maxlen -= len;
232 dst += len;
233 vaddr += len;
234
235 while (maxlen > AlphaISA::PageBytes) {
236 paddr = vtophys(xc, vaddr);
237 dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr,
238 AlphaISA::PageBytes);
239 assert(dmaaddr);
240
241 char *term = (char *)memchr(dmaaddr, 0, AlphaISA::PageBytes);
242 len = term ? (term - dmaaddr + 1) : AlphaISA::PageBytes;
243
244 memcpy(dst, dmaaddr, len);
245 if (term)
246 return;
247
248 maxlen -= AlphaISA::PageBytes;
249 dst += AlphaISA::PageBytes;
250 vaddr += AlphaISA::PageBytes;
251 }
252
253 if (maxlen > 0) {
254 paddr = vtophys(xc, vaddr);
255 dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, maxlen);
256 assert(dmaaddr);
257
258 char *term = (char *)memchr(dmaaddr, 0, maxlen);
259 len = term ? (term - dmaaddr + 1) : maxlen;
260
261 memcpy(dst, dmaaddr, len);
262
263 maxlen -= len;
264 }
265
266 if (maxlen == 0)
267 dst[maxlen] = '\0';
268 }