blob: 721b23036410e80ab18c60ea8ef466058ffcd57e [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. */
Andrew Scullc66a04d2018-12-07 13:41:56 +000053 pte_t pte = pa_addr(pa) | attrs;
Andrew Scull1ba470e2018-10-31 15:14:31 +000054 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{
Andrew Scullc66a04d2018-12-07 13:41:56 +000069 /* TODO: model attributes. */
70 return arch_mm_pte_is_valid(pte, level);
71}
72
73bool arch_mm_pte_is_valid(pte_t pte, int level)
74{
Andrew Scull1ba470e2018-10-31 15:14:31 +000075 (void)level;
76 return (pte & 0x1) != 0;
77}
78
79bool arch_mm_pte_is_table(pte_t pte, int level)
80{
81 /* Level 0 only contains pages so cannot be a table. */
82 return level != 0 && (pte & 0x3) == 0x3;
83}
84
85bool arch_mm_pte_is_block(pte_t pte, int level)
86{
87 /* Single pages are encoded differently to larger blocks. */
Andrew Scullc66a04d2018-12-07 13:41:56 +000088 return (level == 0 ? (pte & 0x2) != 0
89 : arch_mm_pte_is_present(pte, level) &&
90 !arch_mm_pte_is_table(pte, level));
Andrew Scull1ba470e2018-10-31 15:14:31 +000091}
92
93static uint64_t hf_arch_fake_mm_clear_pte_attrs(pte_t pte)
94{
95 return pte & ~0x3;
96}
97
98paddr_t arch_mm_clear_pa(paddr_t pa)
99{
100 /* This is assumed to round down to the page boundary. */
101 return pa_init(hf_arch_fake_mm_clear_pte_attrs(pa_addr(pa)) &
102 ~((1 << PAGE_BITS) - 1));
103}
104
105paddr_t arch_mm_block_from_pte(pte_t pte)
106{
107 return pa_init(hf_arch_fake_mm_clear_pte_attrs(pte));
108}
109
110paddr_t arch_mm_table_from_pte(pte_t pte)
111{
112 return pa_init(hf_arch_fake_mm_clear_pte_attrs(pte));
113}
114
115uint64_t arch_mm_pte_attrs(pte_t pte)
116{
Andrew Scullc66a04d2018-12-07 13:41:56 +0000117 /* Attributes are not modelled fully. */
118 return pte & 0x1;
Andrew Scull1ba470e2018-10-31 15:14:31 +0000119}
120
121uint64_t arch_mm_combine_table_entry_attrs(uint64_t table_attrs,
122 uint64_t block_attrs)
123{
124 return table_attrs | block_attrs;
125}
126
127void arch_mm_invalidate_stage1_range(vaddr_t va_begin, vaddr_t va_end)
128{
129 /* There's no modelling of the stage-1 TLB. */
130}
131
132void arch_mm_invalidate_stage2_range(ipaddr_t va_begin, ipaddr_t va_end)
133{
134 /* There's no modelling of the stage-2 TLB. */
135}
136
137uint8_t arch_mm_max_level(int mode)
138{
139 /* All modes have 3 levels in the page table. */
140 (void)mode;
141 return 2;
142}
143
144uint8_t arch_mm_root_table_count(int mode)
145{
146 /* Stage 1 has no concatenated tables but stage 2 has 4 of them. */
147 return (mode & MM_MODE_STAGE1) ? 1 : 4;
148}
149
150uint64_t arch_mm_mode_to_attrs(int mode)
151{
Andrew Scullc66a04d2018-12-07 13:41:56 +0000152 /* Attributes are not modelled fully. */
153 return mode & MM_MODE_INVALID ? 0 : 0x1;
Andrew Scull1ba470e2018-10-31 15:14:31 +0000154}
155
156bool arch_mm_init(paddr_t table, bool first)
157{
158 /* No initialization required. */
159 (void)table;
160 (void)first;
161 return true;
162}