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