Initial tests of the arch interface.
These tests use hftest running as the hypervisor by making hftest
retargetable to this new context.
Change-Id: Ie0472932b8156d57913286cc30de7a2d2db32149
diff --git a/test/arch/mm_test.c b/test/arch/mm_test.c
new file mode 100644
index 0000000..4af0c7a
--- /dev/null
+++ b/test/arch/mm_test.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hf/mm.h"
+
+#include "hf/arch/mm.h"
+
+#include "hftest.h"
+
+/** There must be at least two levels in the page table. */
+#define MAX_LEVEL_LOWER_BOUND 1
+
+/**
+ * This is the number of levels that are tested and is constrained as it
+ * controls the depth of recursion in the memory management code.
+ */
+#define MAX_LEVEL_UPPER_BOUND 3
+
+/** X macro to expand tests for all levels. */
+#define EXPAND_LEVEL_TESTS \
+ LEVEL_TEST(0) \
+ LEVEL_TEST(1) \
+ LEVEL_TEST(2) \
+ LEVEL_TEST(3)
+
+/* TODO: work out how to run these test against the host fake arch. */
+
+/**
+ * A block must be allowed at level 0 as this is the level which represents
+ * pages.
+ */
+TEST(arch_mm, block_allowed_at_level0)
+{
+ ASSERT_TRUE(arch_mm_is_block_allowed(0));
+}
+
+/**
+ * The maximum level must be within acceptable bounds.
+ */
+TEST(arch_mm, max_level_stage1)
+{
+ int mode = MM_MODE_STAGE1;
+ uint8_t max_level = arch_mm_max_level(mode);
+ EXPECT_GE(max_level, MAX_LEVEL_LOWER_BOUND);
+ EXPECT_LE(max_level, MAX_LEVEL_UPPER_BOUND);
+}
+
+/* TODO: initialize arch_mm and check max level of stage-2. */
+
+/**
+ * A block is present and mutually exclusive from a table.
+ */
+#define LEVEL_TEST(lvl) \
+ TEST(arch_mm, block_properties_level##lvl) \
+ { \
+ uint8_t level = lvl; \
+ uint64_t attrs = arch_mm_mode_to_attrs(0); \
+ pte_t block_pte; \
+ \
+ /* Test doesn't apply if a block is not allowed. */ \
+ if (!arch_mm_is_block_allowed(level)) { \
+ return; \
+ } \
+ \
+ block_pte = arch_mm_block_pte(level, pa_init(0x12345678000), \
+ attrs); \
+ \
+ EXPECT_TRUE(arch_mm_pte_is_present(block_pte, level)); \
+ EXPECT_TRUE(arch_mm_pte_is_block(block_pte, level)); \
+ EXPECT_FALSE(arch_mm_pte_is_table(block_pte, level)); \
+ }
+EXPAND_LEVEL_TESTS
+#undef LEVEL_TEST