smmu_v3_ptops.cc revision 14100:6ef1220dc6da
12810SN/A/*
210028SGiacomo.Gabrielli@arm.com * Copyright (c) 2013, 2018-2019 ARM Limited
310028SGiacomo.Gabrielli@arm.com * All rights reserved
410028SGiacomo.Gabrielli@arm.com *
510028SGiacomo.Gabrielli@arm.com * The license below extends only to copyright in the software and shall
610028SGiacomo.Gabrielli@arm.com * not be construed as granting a license to any other intellectual
710028SGiacomo.Gabrielli@arm.com * property including but not limited to intellectual property relating
810028SGiacomo.Gabrielli@arm.com * to a hardware implementation of the functionality of the software
910028SGiacomo.Gabrielli@arm.com * licensed hereunder.  You may use the software subject to the license
1010028SGiacomo.Gabrielli@arm.com * terms below provided that you ensure that this notice is replicated
1110028SGiacomo.Gabrielli@arm.com * unmodified and in its entirety in all distributions of the software,
1210028SGiacomo.Gabrielli@arm.com * modified or unmodified, in source code or in binary form.
1310028SGiacomo.Gabrielli@arm.com *
142810SN/A * Redistribution and use in source and binary forms, with or without
152810SN/A * modification, are permitted provided that the following conditions are
162810SN/A * met: redistributions of source code must retain the above copyright
172810SN/A * notice, this list of conditions and the following disclaimer;
182810SN/A * redistributions in binary form must reproduce the above copyright
192810SN/A * notice, this list of conditions and the following disclaimer in the
202810SN/A * documentation and/or other materials provided with the distribution;
212810SN/A * neither the name of the copyright holders nor the names of its
222810SN/A * contributors may be used to endorse or promote products derived from
232810SN/A * this software without specific prior written permission.
242810SN/A *
252810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362810SN/A *
372810SN/A * Authors: Stan Czerniawski
382810SN/A */
392810SN/A
402810SN/A#include "dev/arm/smmu_v3_ptops.hh"
412810SN/A
422810SN/A#include "base/bitfield.hh"
432810SN/A#include "base/logging.hh"
442810SN/A
452810SN/Abool
462810SN/AV7LPageTableOps::isValid(pte_t pte, unsigned level) const
472810SN/A{
482810SN/A    switch (level) {
498232Snate@binkert.org        case 1: return  pte & 0x1;
505338Sstever@gmail.com        case 2: return  pte & 0x1;
512810SN/A        case 3: return (pte & 0x1) && (pte & 0x2);
5210623Smitch.hayenga@arm.com        default: panic("bad level %d", level);
5310623Smitch.hayenga@arm.com    }
5410623Smitch.hayenga@arm.com}
5510623Smitch.hayenga@arm.com
5610623Smitch.hayenga@arm.combool
5710623Smitch.hayenga@arm.comV7LPageTableOps::isLeaf(pte_t pte, unsigned level) const
5810623Smitch.hayenga@arm.com{
5910623Smitch.hayenga@arm.com    switch (level) {
6010623Smitch.hayenga@arm.com        case 1: return !(pte & 0x2);
6110623Smitch.hayenga@arm.com        case 2: return !(pte & 0x2);
6210623Smitch.hayenga@arm.com        case 3: return true;
6310623Smitch.hayenga@arm.com        default: panic("bad level %d", level);
6410623Smitch.hayenga@arm.com    }
6510623Smitch.hayenga@arm.com}
6610623Smitch.hayenga@arm.com
6710623Smitch.hayenga@arm.combool
6810623Smitch.hayenga@arm.comV7LPageTableOps::isWritable(pte_t pte, unsigned level, bool stage2) const
6910623Smitch.hayenga@arm.com{
7010623Smitch.hayenga@arm.com    return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0;
7110623Smitch.hayenga@arm.com}
7210623Smitch.hayenga@arm.com
7310623Smitch.hayenga@arm.comAddr
7410623Smitch.hayenga@arm.comV7LPageTableOps::nextLevelPointer(pte_t pte, unsigned level) const
7510623Smitch.hayenga@arm.com{
7610623Smitch.hayenga@arm.com    if (isLeaf(pte, level)) {
7710623Smitch.hayenga@arm.com        switch (level) {
7810623Smitch.hayenga@arm.com            case 1: return mbits(pte, 39, 30);
7910623Smitch.hayenga@arm.com            case 2: return mbits(pte, 39, 21);
8010623Smitch.hayenga@arm.com            case 3: return mbits(pte, 39, 12);
8110623Smitch.hayenga@arm.com            default: panic("bad level %d", level);
8210623Smitch.hayenga@arm.com        }
8310623Smitch.hayenga@arm.com    } else {
8410623Smitch.hayenga@arm.com        return mbits(pte, 39, 12);
853861SN/A    }
8610623Smitch.hayenga@arm.com}
8710623Smitch.hayenga@arm.com
883861SN/AAddr
895875Ssteve.reinhardt@amd.comV7LPageTableOps::index(Addr va, unsigned level) const
9010623Smitch.hayenga@arm.com{
915875Ssteve.reinhardt@amd.com    // In theory this should be configurable...
925875Ssteve.reinhardt@amd.com    const int n = 12;
932810SN/A
9410623Smitch.hayenga@arm.com    switch (level) {
9510623Smitch.hayenga@arm.com        case 1: return bits(va, 26+n, 30) << 3; break;
9610623Smitch.hayenga@arm.com        case 2: return bits(va, 29, 21) << 3; break;
9710028SGiacomo.Gabrielli@arm.com        case 3: return bits(va, 20, 12) << 3; break;
988832SAli.Saidi@ARM.com        default: panic("bad level %d", level);
992810SN/A    }
10010623Smitch.hayenga@arm.com}
10110053Smitch.hayenga+gem5@gmail.com
10210623Smitch.hayenga@arm.comAddr
10310623Smitch.hayenga@arm.comV7LPageTableOps::pageMask(pte_t pte, unsigned level) const
1043861SN/A{
10510623Smitch.hayenga@arm.com    switch (level) {
1065875Ssteve.reinhardt@amd.com        case 1: return ~mask(30);
10710623Smitch.hayenga@arm.com        case 2: return ~mask(21);
10810623Smitch.hayenga@arm.com        case 3: return bits(pte, 52) ? ~mask(16) : ~mask(12);
1093861SN/A        default: panic("bad level %d", level);
11010623Smitch.hayenga@arm.com    }
1115875Ssteve.reinhardt@amd.com}
11210623Smitch.hayenga@arm.com
11310623Smitch.hayenga@arm.comAddr
1145875Ssteve.reinhardt@amd.comV7LPageTableOps::walkMask(unsigned level) const
11510623Smitch.hayenga@arm.com{
11610623Smitch.hayenga@arm.com    switch (level) {
11710623Smitch.hayenga@arm.com        case 1: return mask(39, 30);
11810623Smitch.hayenga@arm.com        case 2: return mask(39, 21);
11910623Smitch.hayenga@arm.com        case 3: return mask(39, 12);
1205875Ssteve.reinhardt@amd.com        default: panic("bad level %d", level);
1213861SN/A    }
12210623Smitch.hayenga@arm.com}
12310623Smitch.hayenga@arm.com
12410028SGiacomo.Gabrielli@arm.comunsigned
12510623Smitch.hayenga@arm.comV7LPageTableOps::firstLevel(uint8_t tsz) const
1265875Ssteve.reinhardt@amd.com{
12710623Smitch.hayenga@arm.com    return 1;
1285875Ssteve.reinhardt@amd.com}
12910623Smitch.hayenga@arm.com
13010623Smitch.hayenga@arm.comunsigned
1315875Ssteve.reinhardt@amd.comV7LPageTableOps::lastLevel() const
1325875Ssteve.reinhardt@amd.com{
13310623Smitch.hayenga@arm.com    return 3;
1345875Ssteve.reinhardt@amd.com}
13510623Smitch.hayenga@arm.com
13610623Smitch.hayenga@arm.combool
13710623Smitch.hayenga@arm.comV8PageTableOps4k::isValid(pte_t pte, unsigned level) const
13810623Smitch.hayenga@arm.com{
13910623Smitch.hayenga@arm.com    switch (level) {
14010623Smitch.hayenga@arm.com        case 0: return  pte & 0x1;
14110623Smitch.hayenga@arm.com        case 1: return  pte & 0x1;
14210623Smitch.hayenga@arm.com        case 2: return  pte & 0x1;
14310623Smitch.hayenga@arm.com        case 3: return (pte & 0x1) && (pte & 0x2);
14410623Smitch.hayenga@arm.com        default: panic("bad level %d", level);
14510623Smitch.hayenga@arm.com    }
14610623Smitch.hayenga@arm.com}
1475875Ssteve.reinhardt@amd.com
14810623Smitch.hayenga@arm.combool
1495875Ssteve.reinhardt@amd.comV8PageTableOps4k::isLeaf(pte_t pte, unsigned level) const
1505875Ssteve.reinhardt@amd.com{
1515875Ssteve.reinhardt@amd.com    switch (level) {
1525875Ssteve.reinhardt@amd.com        case 0: return false;
1535875Ssteve.reinhardt@amd.com        case 1: return !(pte & 0x2);
15410623Smitch.hayenga@arm.com        case 2: return !(pte & 0x2);
15510028SGiacomo.Gabrielli@arm.com        case 3: return true;
1565875Ssteve.reinhardt@amd.com        default: panic("bad level %d", level);
15710623Smitch.hayenga@arm.com    }
15810623Smitch.hayenga@arm.com}
15910623Smitch.hayenga@arm.com
16010623Smitch.hayenga@arm.combool
16110623Smitch.hayenga@arm.comV8PageTableOps4k::isWritable(pte_t pte, unsigned level, bool stage2) const
16210623Smitch.hayenga@arm.com{
1635875Ssteve.reinhardt@amd.com    return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0;
1643861SN/A}
1658831Smrinmoy.ghosh@arm.com
16610623Smitch.hayenga@arm.comAddr
16710623Smitch.hayenga@arm.comV8PageTableOps4k::nextLevelPointer(pte_t pte, unsigned level) const
16810623Smitch.hayenga@arm.com{
16910623Smitch.hayenga@arm.com    if (isLeaf(pte, level)) {
17010623Smitch.hayenga@arm.com        switch (level) {
17110623Smitch.hayenga@arm.com            // no level 0 here
17210623Smitch.hayenga@arm.com            case 1: return mbits(pte, 47, 30);
17310623Smitch.hayenga@arm.com            case 2: return mbits(pte, 47, 21);
17410623Smitch.hayenga@arm.com            case 3: return mbits(pte, 47, 12);
17510623Smitch.hayenga@arm.com            default: panic("bad level %d", level);
17610623Smitch.hayenga@arm.com        }
17710623Smitch.hayenga@arm.com    } else {
17810623Smitch.hayenga@arm.com        return mbits(pte, 47, 12);
17910623Smitch.hayenga@arm.com    }
18010623Smitch.hayenga@arm.com}
18110623Smitch.hayenga@arm.com
18210623Smitch.hayenga@arm.comAddr
18310623Smitch.hayenga@arm.comV8PageTableOps4k::index(Addr va, unsigned level) const
18410623Smitch.hayenga@arm.com{
18510623Smitch.hayenga@arm.com    switch (level) {
18610623Smitch.hayenga@arm.com        case 0: return bits(va, 47, 39) << 3; break;
18710623Smitch.hayenga@arm.com        case 1: return bits(va, 38, 30) << 3; break;
18810623Smitch.hayenga@arm.com        case 2: return bits(va, 29, 21) << 3; break;
18910623Smitch.hayenga@arm.com        case 3: return bits(va, 20, 12) << 3; break;
19010623Smitch.hayenga@arm.com        default: panic("bad level %d", level);
19110623Smitch.hayenga@arm.com    }
19210623Smitch.hayenga@arm.com}
19310623Smitch.hayenga@arm.com
19410623Smitch.hayenga@arm.comAddr
19510623Smitch.hayenga@arm.comV8PageTableOps4k::pageMask(pte_t pte, unsigned level) const
19610623Smitch.hayenga@arm.com{
19710623Smitch.hayenga@arm.com    switch (level) {
19810623Smitch.hayenga@arm.com        // no level 0 here
19910623Smitch.hayenga@arm.com        case 1: return ~mask(30);
20010623Smitch.hayenga@arm.com        case 2: return ~mask(21);
20110623Smitch.hayenga@arm.com        case 3: return bits(pte, 52) ? ~mask(16) : ~mask(12);
2028831Smrinmoy.ghosh@arm.com        default: panic("bad level %d", level);
2038831Smrinmoy.ghosh@arm.com    }
2048831Smrinmoy.ghosh@arm.com}
2058831Smrinmoy.ghosh@arm.com
20610623Smitch.hayenga@arm.comAddr
2078831Smrinmoy.ghosh@arm.comV8PageTableOps4k::walkMask(unsigned level) const
208{
209    switch (level) {
210        case 0: return mask(47, 39);
211        case 1: return mask(47, 30);
212        case 2: return mask(47, 21);
213        case 3: return mask(47, 12);
214        default: panic("bad level %d", level);
215    }
216}
217
218unsigned
219V8PageTableOps4k::firstLevel(uint8_t tsz) const
220{
221    if (tsz >= 16 && tsz <= 24) return 0;
222    if (tsz >= 25 && tsz <= 33) return 1;
223    if (tsz >= 34 && tsz <= 39) return 2;
224
225    panic("Unsupported TnSZ: %d\n", tsz);
226}
227
228unsigned
229V8PageTableOps4k::lastLevel() const
230{
231    return 3;
232}
233
234bool
235V8PageTableOps16k::isValid(pte_t pte, unsigned level) const
236{
237    switch (level) {
238        case 0: return  pte & 0x1;
239        case 1: return  pte & 0x1;
240        case 2: return  pte & 0x1;
241        case 3: return (pte & 0x1) && (pte & 0x2);
242        default: panic("bad level %d", level);
243    }
244}
245
246bool
247V8PageTableOps16k::isLeaf(pte_t pte, unsigned level) const
248{
249    switch (level) {
250        case 0: return false;
251        case 1: return false;
252        case 2: return !(pte & 0x2);
253        case 3: return true;
254        default: panic("bad level %d", level);
255    }
256}
257
258bool
259V8PageTableOps16k::isWritable(pte_t pte, unsigned level, bool stage2) const
260{
261    return stage2 ? bits(pte, 7, 6) == 3 : bits(pte, 7) == 0;
262}
263
264Addr
265V8PageTableOps16k::nextLevelPointer(pte_t pte, unsigned level) const
266{
267    if (isLeaf(pte, level)) {
268        switch (level) {
269            // no level 0 here
270            case 1: return mbits(pte, 47, 36);
271            case 2: return mbits(pte, 47, 25);
272            case 3: return mbits(pte, 47, 14);
273            default: panic("bad level %d", level);
274        }
275    } else {
276        return mbits(pte, 47, 12);
277    }
278}
279
280Addr
281V8PageTableOps16k::index(Addr va, unsigned level) const
282{
283    switch (level) {
284        case 0: return bits(va, 47, 47) << 3; break;
285        case 1: return bits(va, 46, 36) << 3; break;
286        case 2: return bits(va, 35, 25) << 3; break;
287        case 3: return bits(va, 24, 14) << 3; break;
288        default: panic("bad level %d", level);
289    }
290}
291
292Addr
293V8PageTableOps16k::pageMask(pte_t pte, unsigned level) const
294{
295    switch (level) {
296        // no level 0 here
297        case 1: return ~mask(36);
298        // 16K granule supports contiguous entries also at L2; - 1G
299        case 2: return bits(pte, 52) ? ~mask(30) : ~mask(25);
300        // as well as at L3; - 2M
301        case 3: return bits(pte, 52) ? ~mask(21) : ~mask(14);
302        default: panic("bad level %d", level);
303    }
304}
305
306Addr
307V8PageTableOps16k::walkMask(unsigned level) const
308{
309    switch (level) {
310        case 0: return ~mask(47);
311        case 1: return ~mask(36);
312        case 2: return ~mask(25);
313        case 3: return ~mask(14);
314        default: panic("bad level %d", level);
315    }
316}
317
318unsigned
319V8PageTableOps16k::firstLevel(uint8_t tsz) const
320{
321    if (tsz == 16) return 0;
322    if (tsz >= 17 && tsz <= 27) return 1;
323    if (tsz >= 28 && tsz <= 38) return 2;
324    if (tsz == 39) return 3;
325
326    panic("Unsupported TnSZ: %d\n", tsz);
327}
328
329unsigned
330V8PageTableOps16k::lastLevel() const
331{
332    return 3;
333}
334
335bool
336V8PageTableOps64k::isValid(pte_t pte, unsigned level) const
337{
338    switch (level) {
339        case 1: return  pte & 0x1;
340        case 2: return  pte & 0x1;
341        case 3: return (pte & 0x1) && (pte & 0x2);
342        default: panic("bad level %d", level);
343    }
344}
345
346bool
347V8PageTableOps64k::isLeaf(pte_t pte, unsigned level) const
348{
349    switch (level) {
350        case 1: return false;
351        case 2: return !(pte & 0x2);
352        case 3: return true;
353        default: panic("bad level %d", level);
354    }
355}
356
357bool
358V8PageTableOps64k::isWritable(pte_t pte, unsigned level, bool stage2) const
359{
360    return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0;
361}
362
363Addr
364V8PageTableOps64k::nextLevelPointer(pte_t pte, unsigned level) const
365{
366    if (isLeaf(pte, level)) {
367        switch (level) {
368            // no level 1 here
369            case 2: return mbits(pte, 47, 29);
370            case 3: return mbits(pte, 47, 16);
371            default: panic("bad level %d", level);
372        }
373    } else {
374        return mbits(pte, 47, 16);
375    }
376}
377
378Addr
379V8PageTableOps64k::index(Addr va, unsigned level) const
380{
381    switch (level) {
382        case 1: return bits(va, 47, 42) << 3; break;
383        case 2: return bits(va, 41, 29) << 3; break;
384        case 3: return bits(va, 28, 16) << 3; break;
385        default: panic("bad level %d", level);
386    }
387}
388
389Addr
390V8PageTableOps64k::pageMask(pte_t pte, unsigned level) const
391{
392    switch (level) {
393        // no level 1 here
394        case 2: return ~mask(29);
395        case 3: return bits(pte, 52) ? ~mask(21) : ~mask(16);
396        default: panic("bad level %d", level);
397    }
398}
399
400Addr
401V8PageTableOps64k::walkMask(unsigned level) const
402{
403    switch (level) {
404        case 1: return mask(47, 42);
405        case 2: return mask(47, 29);
406        case 3: return mask(47, 16);
407        default: panic("bad level %d", level);
408    }
409}
410
411unsigned
412V8PageTableOps64k::firstLevel(uint8_t tsz) const
413{
414    if (tsz >= 12 && tsz <= 21) return 1;
415    if (tsz >= 22 && tsz <= 34) return 2;
416    if (tsz >= 35 && tsz <= 39) return 3;
417
418    panic("Unsupported TnSZ: %d\n", tsz);
419}
420
421unsigned
422V8PageTableOps64k::lastLevel() const
423{
424    return 3;
425}
426