1 /*
2 * Copyright 2018 The Hafnium Authors.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
7 */
8
9 #include "hf/mm.h"
10
11 #include "hf/arch/mm.h"
12
13 #include "test/hftest.h"
14
15 /** There must be at least two levels in the page table. */
16 #define MAX_LEVEL_LOWER_BOUND 1
17
18 /**
19 * This is the number of levels that are tested and is constrained as it
20 * controls the depth of recursion in the memory management code.
21 */
22 #define MAX_LEVEL_UPPER_BOUND 3
23
24 /** X macro to expand tests for all levels. */
25 #define EXPAND_LEVEL_TESTS \
26 LEVEL_TEST(0) \
27 LEVEL_TEST(1) \
28 LEVEL_TEST(2) \
29 LEVEL_TEST(3)
30
31 /* TODO: work out how to run these test against the host fake arch. */
32
33 /**
34 * A block must be allowed at level 0 as this is the level which represents
35 * pages.
36 */
TEST(arch_mm,block_allowed_at_level0)37 TEST(arch_mm, block_allowed_at_level0)
38 {
39 ASSERT_TRUE(arch_mm_is_block_allowed(0));
40 }
41
42 /**
43 * The maximum level must be within acceptable bounds.
44 */
TEST(arch_mm,max_level_stage1)45 TEST(arch_mm, max_level_stage1)
46 {
47 uint8_t max_level;
48
49 arch_mm_stage1_max_level_set(arch_mm_get_pa_range());
50 max_level = arch_mm_stage1_max_level();
51
52 EXPECT_GE(max_level, MAX_LEVEL_LOWER_BOUND);
53 EXPECT_LE(max_level, MAX_LEVEL_UPPER_BOUND);
54 }
55
56 /* TODO: initialize arch_mm and check max level of stage-2. */
57
58 /**
59 * An absent entry is not present, valid, a block nor a table.
60 */
61 #define LEVEL_TEST(lvl) \
62 TEST(arch_mm, absent_properties_level##lvl) \
63 { \
64 uint8_t level = lvl; \
65 pte_t absent_pte; \
66 \
67 absent_pte = arch_mm_absent_pte(level); \
68 \
69 EXPECT_FALSE(arch_mm_pte_is_present(absent_pte, level)); \
70 EXPECT_FALSE(arch_mm_pte_is_valid(absent_pte, level)); \
71 EXPECT_FALSE(arch_mm_pte_is_block(absent_pte, level)); \
72 EXPECT_FALSE(arch_mm_pte_is_table(absent_pte, level)); \
73 }
74 EXPAND_LEVEL_TESTS
75 #undef LEVEL_TEST
76
77 /**
78 * An invalid block is present and mutually exclusive from a table.
79 */
80 #define LEVEL_TEST(lvl) \
81 TEST(arch_mm, invalid_block_properties_level##lvl) \
82 { \
83 uint8_t level = lvl; \
84 uint64_t attrs = \
85 arch_mm_mode_to_stage2_attrs(MM_MODE_INVALID); \
86 pte_t block_pte; \
87 \
88 /* Test doesn't apply if a block is not allowed. */ \
89 if (!arch_mm_is_block_allowed(level)) { \
90 return; \
91 } \
92 \
93 block_pte = arch_mm_block_pte(level, pa_init(PAGE_SIZE * 19), \
94 attrs); \
95 \
96 EXPECT_TRUE(arch_mm_pte_is_present(block_pte, level)); \
97 EXPECT_FALSE(arch_mm_pte_is_valid(block_pte, level)); \
98 EXPECT_TRUE(arch_mm_pte_is_block(block_pte, level)); \
99 EXPECT_FALSE(arch_mm_pte_is_table(block_pte, level)); \
100 }
101 EXPAND_LEVEL_TESTS
102 #undef LEVEL_TEST
103
104 /**
105 * A valid block is present and mutually exclusive from a table.
106 */
107 #define LEVEL_TEST(lvl) \
108 TEST(arch_mm, valid_block_properties_level##lvl) \
109 { \
110 uint8_t level = lvl; \
111 uint64_t attrs = arch_mm_mode_to_stage2_attrs(0); \
112 pte_t block_pte; \
113 \
114 /* Test doesn't apply if a block is not allowed. */ \
115 if (!arch_mm_is_block_allowed(level)) { \
116 return; \
117 } \
118 \
119 block_pte = arch_mm_block_pte( \
120 level, pa_init(PAGE_SIZE * 12345678U), attrs); \
121 \
122 EXPECT_TRUE(arch_mm_pte_is_present(block_pte, level)); \
123 EXPECT_TRUE(arch_mm_pte_is_valid(block_pte, level)); \
124 EXPECT_TRUE(arch_mm_pte_is_block(block_pte, level)); \
125 EXPECT_FALSE(arch_mm_pte_is_table(block_pte, level)); \
126 }
127 EXPAND_LEVEL_TESTS
128 #undef LEVEL_TEST
129
130 /**
131 * A table is present, valid and mutually exclusive from a block.
132 */
133 #define LEVEL_TEST(lvl) \
134 TEST(arch_mm, table_properties_level##lvl) \
135 { \
136 uint8_t level = lvl; \
137 pte_t table_pte; \
138 \
139 /* Test doesn't apply to level 0 as there can't be a table. */ \
140 if (level == 0) { \
141 return; \
142 } \
143 \
144 table_pte = arch_mm_table_pte( \
145 level, pa_init(PAGE_SIZE * 999999999U)); \
146 \
147 EXPECT_TRUE(arch_mm_pte_is_present(table_pte, level)); \
148 EXPECT_TRUE(arch_mm_pte_is_valid(table_pte, level)); \
149 EXPECT_FALSE(arch_mm_pte_is_block(table_pte, level)); \
150 EXPECT_TRUE(arch_mm_pte_is_table(table_pte, level)); \
151 }
152 EXPAND_LEVEL_TESTS
153 #undef LEVEL_TEST
154
155 /**
156 * The address and attributes of a block must be preserved when encoding and
157 * decoding.
158 */
159 #define LEVEL_TEST(lvl) \
160 TEST(arch_mm, block_addr_and_attrs_preserved_level##lvl) \
161 { \
162 uint8_t level = lvl; \
163 paddr_t addr; \
164 uint64_t attrs; \
165 pte_t block_pte; \
166 \
167 /* Test doesn't apply if a block is not allowed. */ \
168 if (!arch_mm_is_block_allowed(level)) { \
169 return; \
170 } \
171 \
172 addr = pa_init(0); \
173 attrs = arch_mm_mode_to_stage2_attrs(0); \
174 block_pte = arch_mm_block_pte(level, addr, attrs); \
175 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs); \
176 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)), \
177 pa_addr(addr)); \
178 \
179 addr = pa_init(PAGE_SIZE * 17); \
180 attrs = arch_mm_mode_to_stage2_attrs(MM_MODE_INVALID); \
181 block_pte = arch_mm_block_pte(level, addr, attrs); \
182 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs); \
183 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)), \
184 pa_addr(addr)); \
185 \
186 addr = pa_init(PAGE_SIZE * 500); \
187 attrs = arch_mm_mode_to_stage2_attrs(MM_MODE_R | MM_MODE_W); \
188 block_pte = arch_mm_block_pte(level, addr, attrs); \
189 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs); \
190 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)), \
191 pa_addr(addr)); \
192 }
193 EXPAND_LEVEL_TESTS
194 #undef LEVEL_TEST
195