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 ROOT_LEVEL_LOWER_BOUND 2
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 ROOT_LEVEL_UPPER_BOUND 4
23
24 /* TODO: work out how to run these test against the host fake arch. */
25
26 /**
27 * A block must be allowed at level 0 as this is the level which represents
28 * pages.
29 */
TEST(arch_mm,block_allowed_at_level0)30 TEST(arch_mm, block_allowed_at_level0)
31 {
32 ASSERT_TRUE(arch_mm_is_block_allowed(0));
33 }
34
35 /**
36 * The root level must be within acceptable bounds.
37 */
TEST(arch_mm,root_level_stage1)38 TEST(arch_mm, root_level_stage1)
39 {
40 uint32_t pa_bits = arch_mm_get_pa_bits(arch_mm_get_pa_range());
41 mm_attr_t root_level;
42
43 arch_mm_stage1_root_level_set(pa_bits);
44 root_level = arch_mm_stage1_root_level();
45
46 EXPECT_GE(root_level, ROOT_LEVEL_LOWER_BOUND);
47 EXPECT_LE(root_level, ROOT_LEVEL_UPPER_BOUND);
48 }
49
50 /* TODO: initialize arch_mm and check max level of stage-2. */
51
52 /**
53 * An absent entry is not present, valid, a block nor a table.
54 */
TEST(arch_mm,absent_properties)55 TEST(arch_mm, absent_properties)
56 {
57 for (mm_level_t level = 0; level <= ROOT_LEVEL_UPPER_BOUND; level++) {
58 pte_t absent_pte;
59
60 absent_pte = arch_mm_absent_pte(level);
61
62 EXPECT_EQ(arch_mm_pte_type(absent_pte, level), PTE_TYPE_ABSENT);
63 EXPECT_FALSE(arch_mm_pte_is_present(absent_pte, level));
64 EXPECT_FALSE(arch_mm_pte_is_valid(absent_pte, level));
65 EXPECT_FALSE(arch_mm_pte_is_block(absent_pte, level));
66 EXPECT_FALSE(arch_mm_pte_is_table(absent_pte, level));
67 }
68 }
69
70 /**
71 * An invalid block is present and mutually exclusive from a table.
72 */
TEST(arch_mm,invalid_block_properties)73 TEST(arch_mm, invalid_block_properties)
74 {
75 for (mm_level_t level = 0; level <= ROOT_LEVEL_UPPER_BOUND; level++) {
76 mm_attr_t attrs = arch_mm_mode_to_stage2_attrs(MM_MODE_INVALID);
77 pte_t block_pte;
78
79 /* Test doesn't apply if a block is not allowed. */
80 if (!arch_mm_is_block_allowed(level)) {
81 continue;
82 }
83
84 block_pte = arch_mm_block_pte(level, pa_init(PAGE_SIZE * 19),
85 attrs);
86
87 EXPECT_EQ(arch_mm_pte_type(block_pte, level),
88 PTE_TYPE_INVALID_BLOCK);
89 EXPECT_TRUE(arch_mm_pte_is_present(block_pte, level));
90 EXPECT_FALSE(arch_mm_pte_is_valid(block_pte, level));
91 EXPECT_TRUE(arch_mm_pte_is_block(block_pte, level));
92 EXPECT_FALSE(arch_mm_pte_is_table(block_pte, level));
93 }
94 }
95
96 /**
97 * A valid block is present and mutually exclusive from a table.
98 */
TEST(arch_mm,valid_block_properties)99 TEST(arch_mm, valid_block_properties)
100 {
101 for (mm_level_t level = 0; level <= ROOT_LEVEL_UPPER_BOUND; level++) {
102 mm_attr_t attrs = arch_mm_mode_to_stage2_attrs(0);
103 pte_t block_pte;
104
105 /* Test doesn't apply if a block is not allowed. */
106 if (!arch_mm_is_block_allowed(level)) {
107 continue;
108 }
109
110 block_pte = arch_mm_block_pte(
111 level, pa_init(PAGE_SIZE * 12345678U), attrs);
112
113 EXPECT_EQ(arch_mm_pte_type(block_pte, level),
114 PTE_TYPE_VALID_BLOCK);
115 EXPECT_TRUE(arch_mm_pte_is_present(block_pte, level));
116 EXPECT_TRUE(arch_mm_pte_is_valid(block_pte, level));
117 EXPECT_TRUE(arch_mm_pte_is_block(block_pte, level));
118 EXPECT_FALSE(arch_mm_pte_is_table(block_pte, level));
119 }
120 }
121
122 /**
123 * A table is present, valid and mutually exclusive from a block.
124 */
TEST(arch_mm,table_properties)125 TEST(arch_mm, table_properties)
126 {
127 for (mm_level_t level = 0; level <= ROOT_LEVEL_UPPER_BOUND; level++) {
128 pte_t table_pte;
129
130 /* Test doesn't apply to level 0 as there can't be a table. */
131 if (level == 0) {
132 continue;
133 }
134
135 table_pte = arch_mm_table_pte(level,
136 pa_init(PAGE_SIZE * 999999999U));
137
138 EXPECT_EQ(arch_mm_pte_type(table_pte, level), PTE_TYPE_TABLE);
139 EXPECT_TRUE(arch_mm_pte_is_present(table_pte, level));
140 EXPECT_TRUE(arch_mm_pte_is_valid(table_pte, level));
141 EXPECT_FALSE(arch_mm_pte_is_block(table_pte, level));
142 EXPECT_TRUE(arch_mm_pte_is_table(table_pte, level));
143 }
144 }
145
146 /**
147 * The address and attributes of a block must be preserved when encoding and
148 * decoding.
149 */
TEST(arch_mm,block_addr_and_attrs_preserved)150 TEST(arch_mm, block_addr_and_attrs_preserved)
151 {
152 for (mm_level_t level = 0; level <= ROOT_LEVEL_UPPER_BOUND; level++) {
153 paddr_t addr;
154 mm_attr_t attrs;
155 pte_t block_pte;
156
157 /* Test doesn't apply if a block is not allowed. */
158 if (!arch_mm_is_block_allowed(level)) {
159 continue;
160 }
161
162 addr = pa_init(0);
163 attrs = arch_mm_mode_to_stage2_attrs(0);
164 block_pte = arch_mm_block_pte(level, addr, attrs);
165 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs);
166 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)),
167 pa_addr(addr));
168
169 addr = pa_init(PAGE_SIZE * 17);
170 attrs = arch_mm_mode_to_stage2_attrs(MM_MODE_INVALID);
171 block_pte = arch_mm_block_pte(level, addr, attrs);
172 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs);
173 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)),
174 pa_addr(addr));
175
176 addr = pa_init(PAGE_SIZE * 500);
177 attrs = arch_mm_mode_to_stage2_attrs(MM_MODE_R | MM_MODE_W);
178 block_pte = arch_mm_block_pte(level, addr, attrs);
179 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs);
180 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)),
181 pa_addr(addr));
182 }
183 }
184