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