vtophys.cc revision 2159
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
36using namespace std;
37using namespace AlphaISA;
38
39AlphaISA::PageTableEntry
40kernel_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
65Addr
66vtophys(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
81Addr
82vtophys(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
110uint8_t *
111ptomem(ExecContext *xc, Addr paddr, size_t len)
112{
113    return xc->physmem->dma_addr(paddr, len);
114}
115
116uint8_t *
117vtomem(ExecContext *xc, Addr vaddr, size_t len)
118{
119    Addr paddr = vtophys(xc, vaddr);
120    return xc->physmem->dma_addr(paddr, len);
121}
122
123void
124CopyOut(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
165void
166CopyIn(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
207void
208CopyString(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}
266