blob: 81e106f54021237becfb35230c625faae4b5ffab [file] [log] [blame]
Andrew Scull1ba470e2018-10-31 15:14:31 +00001/*
2 * Copyright 2018 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "hf/arch/mm.h"
18
19#include "hf/mm.h"
20
21/*
22 * Our fake architecture has page tables base on those of aarch64:
23 *
24 * - The highest level table is always 2, lowest level is 0.
25 * - Blocks are allowed at all levels.
26 *
27 * There are four kinds of entry:
28 *
29 * 1. Absent: 0
30 * 2. Page, at level 0: <page-aligned address> | <attrs> | 0x3
31 * 3. Block, at level 2 or 1: <block-aligned address> | <attrs> | 0x1
32 * 4. Subtable, at level 2 or 1: <subtable address> | 0x3
33 *
34 * <attrs> are always 0 for now.
35 */
36
37pte_t arch_mm_absent_pte(int level)
38{
39 (void)level;
40 return 0;
41}
42
43pte_t arch_mm_table_pte(int level, paddr_t pa)
44{
45 /* This is the same for all levels. */
46 (void)level;
47 return pa_addr(pa) | 0x3;
48}
49
50pte_t arch_mm_block_pte(int level, paddr_t pa, uint64_t attrs)
51{
52 /* Single pages are encoded differently to larger blocks. */
53 pte_t pte = pa_addr(pa) | attrs | 0x1;
54 if (level == 0) {
55 pte |= 0x2;
56 }
57 return pte;
58}
59
60bool arch_mm_is_block_allowed(int level)
61{
62 /* All levels can have blocks. */
63 (void)level;
64 return true;
65}
66
67bool arch_mm_pte_is_present(pte_t pte, int level)
68{
69 (void)level;
70 return (pte & 0x1) != 0;
71}
72
73bool arch_mm_pte_is_table(pte_t pte, int level)
74{
75 /* Level 0 only contains pages so cannot be a table. */
76 return level != 0 && (pte & 0x3) == 0x3;
77}
78
79bool arch_mm_pte_is_block(pte_t pte, int level)
80{
81 /* Single pages are encoded differently to larger blocks. */
82 return arch_mm_is_block_allowed(level) &&
83 (pte & 0x3) == (level == 0 ? 0x3 : 0x1);
84}
85
86static uint64_t hf_arch_fake_mm_clear_pte_attrs(pte_t pte)
87{
88 return pte & ~0x3;
89}
90
91paddr_t arch_mm_clear_pa(paddr_t pa)
92{
93 /* This is assumed to round down to the page boundary. */
94 return pa_init(hf_arch_fake_mm_clear_pte_attrs(pa_addr(pa)) &
95 ~((1 << PAGE_BITS) - 1));
96}
97
98paddr_t arch_mm_block_from_pte(pte_t pte)
99{
100 return pa_init(hf_arch_fake_mm_clear_pte_attrs(pte));
101}
102
103paddr_t arch_mm_table_from_pte(pte_t pte)
104{
105 return pa_init(hf_arch_fake_mm_clear_pte_attrs(pte));
106}
107
108uint64_t arch_mm_pte_attrs(pte_t pte)
109{
110 /* Attributes are not modelled. */
111 (void)pte;
112 return 0;
113}
114
115uint64_t arch_mm_combine_table_entry_attrs(uint64_t table_attrs,
116 uint64_t block_attrs)
117{
118 return table_attrs | block_attrs;
119}
120
121void arch_mm_invalidate_stage1_range(vaddr_t va_begin, vaddr_t va_end)
122{
123 /* There's no modelling of the stage-1 TLB. */
124}
125
126void arch_mm_invalidate_stage2_range(ipaddr_t va_begin, ipaddr_t va_end)
127{
128 /* There's no modelling of the stage-2 TLB. */
129}
130
131uint8_t arch_mm_max_level(int mode)
132{
133 /* All modes have 3 levels in the page table. */
134 (void)mode;
135 return 2;
136}
137
138uint8_t arch_mm_root_table_count(int mode)
139{
140 /* Stage 1 has no concatenated tables but stage 2 has 4 of them. */
141 return (mode & MM_MODE_STAGE1) ? 1 : 4;
142}
143
144uint64_t arch_mm_mode_to_attrs(int mode)
145{
146 /* Attributes are not modelled. */
147 (void)mode;
148 return 0;
149}
150
151bool arch_mm_init(paddr_t table, bool first)
152{
153 /* No initialization required. */
154 (void)table;
155 (void)first;
156 return true;
157}