blob: bb0337ac8644be8bf6adaaf81e87d762d8890f55 [file] [log] [blame]
Andrew Scull7fd4bb72018-12-08 23:40:12 +00001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2018 The Hafnium Authors.
Andrew Scull7fd4bb72018-12-08 23:40:12 +00003 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * 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.
Andrew Scull7fd4bb72018-12-08 23:40:12 +00007 */
8
9#include "hf/mm.h"
10
11#include "hf/arch/mm.h"
12
Andrew Walbran1e7c7742019-12-13 17:10:02 +000013#include "test/hftest.h"
Andrew Scull7fd4bb72018-12-08 23:40:12 +000014
Fuad Tabbab86325a2020-01-10 13:38:15 +000015/** There must be at least two levels in the page table. */
Andrew Scull7fd4bb72018-12-08 23:40:12 +000016#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 */
37TEST(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 */
45TEST(arch_mm, max_level_stage1)
46{
Andrew Scullda3df7f2019-01-05 17:49:27 +000047 uint8_t max_level = arch_mm_stage1_max_level();
Andrew Scull7fd4bb72018-12-08 23:40:12 +000048 EXPECT_GE(max_level, MAX_LEVEL_LOWER_BOUND);
49 EXPECT_LE(max_level, MAX_LEVEL_UPPER_BOUND);
50}
51
52/* TODO: initialize arch_mm and check max level of stage-2. */
53
54/**
Andrew Scullc66a04d2018-12-07 13:41:56 +000055 * An absent entry is not present, valid, a block nor a table.
Andrew Scull7fd4bb72018-12-08 23:40:12 +000056 */
Andrew Scullc66a04d2018-12-07 13:41:56 +000057#define LEVEL_TEST(lvl) \
58 TEST(arch_mm, absent_properties_level##lvl) \
59 { \
60 uint8_t level = lvl; \
61 pte_t absent_pte; \
62 \
63 absent_pte = arch_mm_absent_pte(level); \
64 \
65 EXPECT_FALSE(arch_mm_pte_is_present(absent_pte, level)); \
66 EXPECT_FALSE(arch_mm_pte_is_valid(absent_pte, level)); \
67 EXPECT_FALSE(arch_mm_pte_is_block(absent_pte, level)); \
68 EXPECT_FALSE(arch_mm_pte_is_table(absent_pte, level)); \
69 }
70EXPAND_LEVEL_TESTS
71#undef LEVEL_TEST
72
73/**
74 * An invalid block is present and mutually exclusive from a table.
75 */
76#define LEVEL_TEST(lvl) \
77 TEST(arch_mm, invalid_block_properties_level##lvl) \
78 { \
79 uint8_t level = lvl; \
Andrew Scullda3df7f2019-01-05 17:49:27 +000080 uint64_t attrs = \
81 arch_mm_mode_to_stage2_attrs(MM_MODE_INVALID); \
Andrew Scullc66a04d2018-12-07 13:41:56 +000082 pte_t block_pte; \
83 \
84 /* Test doesn't apply if a block is not allowed. */ \
85 if (!arch_mm_is_block_allowed(level)) { \
86 return; \
87 } \
88 \
89 block_pte = arch_mm_block_pte(level, pa_init(PAGE_SIZE * 19), \
90 attrs); \
91 \
92 EXPECT_TRUE(arch_mm_pte_is_present(block_pte, level)); \
93 EXPECT_FALSE(arch_mm_pte_is_valid(block_pte, level)); \
94 EXPECT_TRUE(arch_mm_pte_is_block(block_pte, level)); \
95 EXPECT_FALSE(arch_mm_pte_is_table(block_pte, level)); \
96 }
97EXPAND_LEVEL_TESTS
98#undef LEVEL_TEST
99
100/**
101 * A valid block is present and mutually exclusive from a table.
102 */
103#define LEVEL_TEST(lvl) \
104 TEST(arch_mm, valid_block_properties_level##lvl) \
105 { \
106 uint8_t level = lvl; \
Andrew Scullda3df7f2019-01-05 17:49:27 +0000107 uint64_t attrs = arch_mm_mode_to_stage2_attrs(0); \
Andrew Scullc66a04d2018-12-07 13:41:56 +0000108 pte_t block_pte; \
109 \
110 /* Test doesn't apply if a block is not allowed. */ \
111 if (!arch_mm_is_block_allowed(level)) { \
112 return; \
113 } \
114 \
115 block_pte = arch_mm_block_pte( \
116 level, pa_init(PAGE_SIZE * 12345678), attrs); \
117 \
118 EXPECT_TRUE(arch_mm_pte_is_present(block_pte, level)); \
119 EXPECT_TRUE(arch_mm_pte_is_valid(block_pte, level)); \
120 EXPECT_TRUE(arch_mm_pte_is_block(block_pte, level)); \
121 EXPECT_FALSE(arch_mm_pte_is_table(block_pte, level)); \
122 }
123EXPAND_LEVEL_TESTS
124#undef LEVEL_TEST
125
126/**
127 * A table is present, valid and mutually exclusive from a block.
128 */
129#define LEVEL_TEST(lvl) \
130 TEST(arch_mm, table_properties_level##lvl) \
131 { \
132 uint8_t level = lvl; \
133 pte_t table_pte; \
134 \
135 /* Test doesn't apply to level 0 as there can't be a table. */ \
136 if (level == 0) { \
137 return; \
138 } \
139 \
140 table_pte = arch_mm_table_pte(level, \
141 pa_init(PAGE_SIZE * 999999999)); \
142 \
143 EXPECT_TRUE(arch_mm_pte_is_present(table_pte, level)); \
144 EXPECT_TRUE(arch_mm_pte_is_valid(table_pte, level)); \
145 EXPECT_FALSE(arch_mm_pte_is_block(table_pte, level)); \
146 EXPECT_TRUE(arch_mm_pte_is_table(table_pte, level)); \
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000147 }
148EXPAND_LEVEL_TESTS
149#undef LEVEL_TEST
Andrew Scull02b7b782018-12-10 10:47:25 +0000150
151/**
152 * The address and attributes of a block must be preserved when encoding and
153 * decoding.
154 */
Andrew Scull3681b8d2018-12-12 14:22:59 +0000155#define LEVEL_TEST(lvl) \
156 TEST(arch_mm, block_addr_and_attrs_preserved_level##lvl) \
157 { \
158 uint8_t level = lvl; \
159 paddr_t addr; \
160 uint64_t attrs; \
161 pte_t block_pte; \
162 \
163 /* Test doesn't apply if a block is not allowed. */ \
164 if (!arch_mm_is_block_allowed(level)) { \
165 return; \
166 } \
167 \
168 addr = pa_init(0); \
Andrew Scullda3df7f2019-01-05 17:49:27 +0000169 attrs = arch_mm_mode_to_stage2_attrs(0); \
Andrew Scull3681b8d2018-12-12 14:22:59 +0000170 block_pte = arch_mm_block_pte(level, addr, attrs); \
171 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs); \
172 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)), \
173 pa_addr(addr)); \
174 \
175 addr = pa_init(PAGE_SIZE * 17); \
Andrew Scullda3df7f2019-01-05 17:49:27 +0000176 attrs = arch_mm_mode_to_stage2_attrs(MM_MODE_INVALID); \
Andrew Scull3681b8d2018-12-12 14:22:59 +0000177 block_pte = arch_mm_block_pte(level, addr, attrs); \
178 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs); \
179 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)), \
180 pa_addr(addr)); \
181 \
182 addr = pa_init(PAGE_SIZE * 500); \
Andrew Scullda3df7f2019-01-05 17:49:27 +0000183 attrs = arch_mm_mode_to_stage2_attrs(MM_MODE_R | MM_MODE_W); \
Andrew Scull3681b8d2018-12-12 14:22:59 +0000184 block_pte = arch_mm_block_pte(level, addr, attrs); \
185 EXPECT_EQ(arch_mm_pte_attrs(block_pte, level), attrs); \
186 EXPECT_EQ(pa_addr(arch_mm_block_from_pte(block_pte, level)), \
187 pa_addr(addr)); \
Andrew Scull02b7b782018-12-10 10:47:25 +0000188 }
189EXPAND_LEVEL_TESTS
190#undef LEVEL_TEST