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/kokoro/ubuntu/test.sh b/kokoro/ubuntu/test.sh
index 0318a51..be49777 100755
--- a/kokoro/ubuntu/test.sh
+++ b/kokoro/ubuntu/test.sh
@@ -28,7 +28,7 @@
TIMEOUT="timeout --foreground"
OUT="out"
-HFTEST="$TIMEOUT 30s ./test/vm/hftest.py --out $OUT/qemu_aarch64_clang --log $OUT/kokoro_log --initrd"
+HFTEST="$TIMEOUT 30s ./test/hftest/hftest.py --out $OUT/qemu_aarch64_clang --log $OUT/kokoro_log"
# Add prebuilt libc++ to the path.
export LD_LIBRARY_PATH=$PWD/prebuilts/linux-x64/clang/lib64
@@ -40,6 +40,7 @@
| tee $OUT/kokoro_log/unit_tests/sponge_log.log
# Run the tests with a timeout so they can't loop forever.
-$HFTEST gicv3_test
-$HFTEST primary_only_test
-$HFTEST primary_with_secondaries_test
+$HFTEST arch_test
+$HFTEST hafnium --initrd gicv3_test
+$HFTEST hafnium --initrd primary_only_test
+$HFTEST hafnium --initrd primary_with_secondaries_test
diff --git a/project/reference b/project/reference
index f1838a8..75da2d1 160000
--- a/project/reference
+++ b/project/reference
@@ -1 +1 @@
-Subproject commit f1838a83dd68fa47df061d8c68abaed98c002039
+Subproject commit 75da2d171f0641c9a637885423c2ece8a1d08015
diff --git a/src/arch/aarch64/BUILD.gn b/src/arch/aarch64/BUILD.gn
index b6efde9..7254faf 100644
--- a/src/arch/aarch64/BUILD.gn
+++ b/src/arch/aarch64/BUILD.gn
@@ -21,18 +21,25 @@
"exceptions.S",
"hypervisor_entry.S",
"plat_entry.S",
- "smc.S",
]
sources += [
- "cpu.c",
"handler.c",
- "mm.c",
"offsets.c",
]
deps = [
+ ":arch",
":entry",
+ ":smc",
+ ]
+}
+
+# Implementation of the arch interface for aarch64.
+source_set("arch") {
+ sources = [
+ "cpu.c",
+ "mm.c",
]
}
@@ -43,6 +50,13 @@
]
}
+# Make a call to the secure monitor.
+source_set("smc") {
+ sources = [
+ "smc.S",
+ ]
+}
+
# aarch64 implementation of putchar for debugging.
source_set("putchar") {
if (arch_aarch64_use_pl011) {
diff --git a/src/arch/aarch64/handler.c b/src/arch/aarch64/handler.c
index d04a368..c15b550 100644
--- a/src/arch/aarch64/handler.c
+++ b/src/arch/aarch64/handler.c
@@ -23,13 +23,13 @@
#include "msr.h"
#include "psci.h"
+#include "smc.h"
struct hvc_handler_return {
uintreg_t user_ret;
struct vcpu *new;
};
-int32_t smc(uintreg_t arg0, uintreg_t arg1, uintreg_t arg2, uintreg_t arg3);
void cpu_entry(struct cpu *c);
void irq_current_exception(uintreg_t elr, uintreg_t spsr)
diff --git a/src/arch/aarch64/vm/BUILD.gn b/src/arch/aarch64/hftest/BUILD.gn
similarity index 93%
rename from src/arch/aarch64/vm/BUILD.gn
rename to src/arch/aarch64/hftest/BUILD.gn
index b6dee03..63ff813 100644
--- a/src/arch/aarch64/vm/BUILD.gn
+++ b/src/arch/aarch64/hftest/BUILD.gn
@@ -15,9 +15,9 @@
# These components are only used by VMs for aarch64 specific actions.
# Implements image_entry for a simple VM kernel.
-source_set("vm_entry") {
+source_set("entry") {
sources = [
- "vm_entry.S",
+ "entry.S",
]
}
@@ -36,6 +36,6 @@
]
deps = [
- ":hf_call",
+ "//src/arch/aarch64:smc",
]
}
diff --git a/src/arch/aarch64/vm/cpu_entry.S b/src/arch/aarch64/hftest/cpu_entry.S
similarity index 100%
rename from src/arch/aarch64/vm/cpu_entry.S
rename to src/arch/aarch64/hftest/cpu_entry.S
diff --git a/src/arch/aarch64/vm/vm_entry.S b/src/arch/aarch64/hftest/entry.S
similarity index 100%
rename from src/arch/aarch64/vm/vm_entry.S
rename to src/arch/aarch64/hftest/entry.S
diff --git a/src/arch/aarch64/vm/hf_call.S b/src/arch/aarch64/hftest/hf_call.S
similarity index 100%
rename from src/arch/aarch64/vm/hf_call.S
rename to src/arch/aarch64/hftest/hf_call.S
diff --git a/src/arch/aarch64/vm/power_mgmt.c b/src/arch/aarch64/hftest/power_mgmt.c
similarity index 93%
rename from src/arch/aarch64/vm/power_mgmt.c
rename to src/arch/aarch64/hftest/power_mgmt.c
index 50b5e47..05f4061 100644
--- a/src/arch/aarch64/vm/power_mgmt.c
+++ b/src/arch/aarch64/hftest/power_mgmt.c
@@ -21,6 +21,7 @@
#include "vmapi/hf/call.h"
#include "../psci.h"
+#include "../smc.h"
/**
* Holds temporary state used to set up the environment on which CPUs will
@@ -69,7 +70,7 @@
s.arg = arg;
/* Try to start the CPU. */
- if (hf_call(PSCI_CPU_ON, id, (size_t)&vm_cpu_entry_raw, (size_t)&s) !=
+ if (smc(PSCI_CPU_ON, id, (size_t)&vm_cpu_entry_raw, (size_t)&s) !=
PSCI_RETURN_SUCCESS) {
return false;
}
@@ -88,7 +89,7 @@
*/
noreturn void cpu_stop(void)
{
- hf_call(PSCI_CPU_OFF, 0, 0, 0);
+ smc(PSCI_CPU_OFF, 0, 0, 0);
for (;;) {
/* This should never be reached. */
}
@@ -99,7 +100,7 @@
*/
noreturn void shutdown(void)
{
- hf_call(PSCI_SYSTEM_OFF, 0, 0, 0);
+ smc(PSCI_SYSTEM_OFF, 0, 0, 0);
for (;;) {
/* This should never be reached. */
}
diff --git a/src/arch/aarch64/smc.h b/src/arch/aarch64/smc.h
new file mode 100644
index 0000000..0802f69
--- /dev/null
+++ b/src/arch/aarch64/smc.h
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "hf/arch/cpu.h"
+
+int32_t smc(uintreg_t arg0, uintreg_t arg1, uintreg_t arg2, uintreg_t arg3);
diff --git a/test/vm/secondaries/BUILD.gn b/test/arch/BUILD.gn
similarity index 71%
copy from test/vm/secondaries/BUILD.gn
copy to test/arch/BUILD.gn
index cd0ad69..f3496a9 100644
--- a/test/vm/secondaries/BUILD.gn
+++ b/test/arch/BUILD.gn
@@ -13,39 +13,25 @@
# limitations under the License.
import("//build/image/image.gni")
+import("//build/toolchain/platform.gni")
-vm_kernel("echo") {
+group("arch") {
testonly = true
- sources = [
- "echo.c",
- ]
-
deps = [
- "//test/vm:secondary_vm",
+ ":arch_test",
]
}
-vm_kernel("relay_a") {
+hypervisor("arch_test") {
testonly = true
sources = [
- "relay_a.c",
+ "mm_test.c",
]
deps = [
- "//test/vm:secondary_vm",
- ]
-}
-
-vm_kernel("relay_b") {
- testonly = true
-
- sources = [
- "relay_b.c",
- ]
-
- deps = [
- "//test/vm:secondary_vm",
+ "//src/arch/${plat_arch}:arch",
+ "//test/hftest:hftest_hypervisor",
]
}
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
diff --git a/test/hftest/BUILD.gn b/test/hftest/BUILD.gn
new file mode 100644
index 0000000..bc956f8
--- /dev/null
+++ b/test/hftest/BUILD.gn
@@ -0,0 +1,77 @@
+# 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.
+
+import("//build/toolchain/platform.gni")
+
+config("hftest_config") {
+ include_dirs = [ "inc" ]
+}
+
+# Testing framework for a primary vm.
+source_set("hftest_primary_vm") {
+ testonly = true
+
+ public_configs = [ ":hftest_config" ]
+
+ sources = [
+ "hftest.c",
+ ]
+
+ deps = [
+ "//src:common",
+ "//src:dlog",
+ "//src:fdt",
+ "//src:memiter",
+ "//src/arch/${plat_arch}:entry",
+ "//src/arch/${plat_arch}/hftest:entry",
+ "//src/arch/${plat_arch}/hftest:hf_call",
+ "//src/arch/${plat_arch}/hftest:power_mgmt",
+ ]
+}
+
+# Testing framework for a secondary vm. It's currently just a slave VM and
+# can't affect the tests directly.
+source_set("hftest_secondary_vm") {
+ testonly = true
+
+ deps = [
+ "//src:common",
+ "//src:dlog",
+ "//src/arch/${plat_arch}:entry",
+ "//src/arch/${plat_arch}/hftest:entry",
+ "//src/arch/${plat_arch}/hftest:hf_call",
+ "//src/arch/${plat_arch}/hftest:power_mgmt",
+ ]
+}
+
+# Testing framework for a hypervisor.
+source_set("hftest_hypervisor") {
+ testonly = true
+
+ public_configs = [ ":hftest_config" ]
+
+ sources = [
+ "hftest.c",
+ ]
+
+ deps = [
+ "//src:common",
+ "//src:dlog",
+ "//src:fdt",
+ "//src:memiter",
+ "//src/arch/${plat_arch}:entry",
+ "//src/arch/${plat_arch}/hftest:entry",
+ "//src/arch/${plat_arch}/hftest:power_mgmt",
+ ]
+}
diff --git a/test/vm/hftest.c b/test/hftest/hftest.c
similarity index 100%
rename from test/vm/hftest.c
rename to test/hftest/hftest.c
diff --git a/test/vm/hftest.py b/test/hftest/hftest.py
similarity index 89%
rename from test/vm/hftest.py
rename to test/hftest/hftest.py
index d80d26b..4a00a52 100755
--- a/test/vm/hftest.py
+++ b/test/hftest/hftest.py
@@ -32,14 +32,15 @@
import sys
-def qemu(hafnium, initrd, args, log):
+def qemu(image, initrd, args, log):
qemu_args = [
"timeout", "--foreground", "5s",
"./prebuilts/linux-x64/qemu/qemu-system-aarch64", "-M", "virt,gic_version=3", "-cpu",
"cortex-a57", "-smp", "4", "-m", "16M", "-machine", "virtualization=true",
- "-nographic", "-nodefaults", "-serial", "stdio", "-kernel", hafnium,
- "-initrd", initrd
+ "-nographic", "-nodefaults", "-serial", "stdio", "-kernel", image,
]
+ if initrd:
+ qemu_args += ["-initrd", initrd]
if args:
qemu_args += ["-append", args]
# Save the log to a file.
@@ -71,22 +72,27 @@
def Main():
parser = argparse.ArgumentParser()
+ parser.add_argument("image")
parser.add_argument("--out", required=True)
parser.add_argument("--log", required=True)
- parser.add_argument("--initrd", required=True)
+ parser.add_argument("--initrd")
parser.add_argument("--suite")
parser.add_argument("--test")
args = parser.parse_args()
# Resolve some paths.
- hafnium = os.path.join(args.out, "hafnium.bin")
- initrd = os.path.join(args.out, "initrd", args.initrd + ".img")
- log = os.path.join(args.log, args.initrd)
+ image = os.path.join(args.out, args.image + ".bin")
+ initrd = None
+ suite = args.image
+ if args.initrd:
+ initrd = os.path.join(args.out, "initrd", args.initrd + ".img")
+ suite += "_" + args.initrd
+ log = os.path.join(args.log, suite)
ensure_dir(log)
print("Logs saved under", log)
log_file = os.path.join(log, "sponge_log.log")
with open(log_file, "w") as sponge_log:
# Query the tests in the image.
- out = qemu(hafnium, initrd, "json", os.path.join(log, "json.log"))
+ out = qemu(image, initrd, "json", os.path.join(log, "json.log"))
sponge_log.write(out)
sponge_log.write("\r\n\r\n")
hftest_json = "\n".join(hftest_lines(out))
@@ -97,7 +103,7 @@
suite_re = re.compile(args.suite or ".*")
test_re = re.compile(args.test or ".*")
sponge = ET.Element("testsuites")
- sponge.set("name", args.initrd)
+ sponge.set("name", suite)
sponge.set(
"timestamp",
datetime.datetime.now().replace(microsecond=0).isoformat())
@@ -121,7 +127,7 @@
print(" RUN", test)
test_log = os.path.join(log,
suite["name"] + "." + test + ".log")
- out = qemu(hafnium, initrd, "run {} {}".format(
+ out = qemu(image, initrd, "run {} {}".format(
suite["name"], test), test_log)
sponge_log.write(out)
sponge_log.write("\r\n\r\n")
diff --git a/test/vm/hftest.h b/test/hftest/inc/hftest.h
similarity index 97%
rename from test/vm/hftest.h
rename to test/hftest/inc/hftest.h
index 0f10eca..290b467 100644
--- a/test/vm/hftest.h
+++ b/test/hftest/inc/hftest.h
@@ -45,6 +45,9 @@
#define ASSERT_GE(x, y) ASSERT_OP(x, y, >=, true)
#define ASSERT_GT(x, y) ASSERT_OP(x, y, >, true)
+#define ASSERT_TRUE(x) ASSERT_EQ(x, true);
+#define ASSERT_FALSE(x) ASSERT_EQ(x, false);
+
#define EXPECT_EQ(x, y) ASSERT_OP(x, y, ==, false)
#define EXPECT_NE(x, y) ASSERT_OP(x, y, !=, false)
#define EXPECT_LE(x, y) ASSERT_OP(x, y, <=, false)
@@ -52,6 +55,9 @@
#define EXPECT_GE(x, y) ASSERT_OP(x, y, >=, false)
#define EXPECT_GT(x, y) ASSERT_OP(x, y, >, false)
+#define EXPECT_TRUE(x) EXPECT_EQ(x, true);
+#define EXPECT_FALSE(x) EXPECT_EQ(x, false);
+
/*
* This must be used exactly once in a test image to signal to the linker that
* the .hftest section is allowed to be included in the generated image.
diff --git a/test/vm/BUILD.gn b/test/vmapi/BUILD.gn
similarity index 65%
rename from test/vm/BUILD.gn
rename to test/vmapi/BUILD.gn
index 7fe6e6a..84feced 100644
--- a/test/vm/BUILD.gn
+++ b/test/vmapi/BUILD.gn
@@ -15,7 +15,7 @@
import("//build/image/image.gni")
import("//build/toolchain/platform.gni")
-group("vm_tests") {
+group("vmapi") {
testonly = true
deps = [
@@ -24,41 +24,6 @@
]
}
-# Primary VMs host the test framework.
-source_set("hftest_vm") {
- testonly = true
-
- sources = [
- "hftest.c",
- "hftest.h",
- ]
-
- deps = [
- "//src:common",
- "//src:dlog",
- "//src:fdt",
- "//src:memiter",
- "//src/arch/${plat_arch}:entry",
- "//src/arch/${plat_arch}/vm:hf_call",
- "//src/arch/${plat_arch}/vm:power_mgmt",
- "//src/arch/${plat_arch}/vm:vm_entry",
- ]
-}
-
-# Secondary VMs can be used as part of a test in the primary.
-source_set("secondary_vm") {
- testonly = true
-
- deps = [
- "//src:common",
- "//src:dlog",
- "//src/arch/${plat_arch}:entry",
- "//src/arch/${plat_arch}/vm:hf_call",
- "//src/arch/${plat_arch}/vm:power_mgmt",
- "//src/arch/${plat_arch}/vm:vm_entry",
- ]
-}
-
# Tests with no secondary VMs.
vm_kernel("primary_only_test_vm") {
testonly = true
@@ -68,7 +33,7 @@
]
deps = [
- ":hftest_vm",
+ "//test/hftest:hftest_primary_vm",
]
}
@@ -89,7 +54,7 @@
]
deps = [
- ":hftest_vm",
+ "//test/hftest:hftest_primary_vm",
]
}
@@ -108,7 +73,7 @@
]
deps = [
- ":hftest_vm",
+ "//test/hftest:hftest_primary_vm",
]
}
@@ -121,19 +86,19 @@
"1048576",
"1",
"relay_a",
- "//test/vm/secondaries:relay_a",
+ "//test/vmapi/secondaries:relay_a",
],
[
"1048576",
"1",
"relay_b",
- "//test/vm/secondaries:relay_b",
+ "//test/vmapi/secondaries:relay_b",
],
[
"1048576",
"1",
"echo",
- "//test/vm/secondaries:echo",
+ "//test/vmapi/secondaries:echo",
],
]
}
diff --git a/test/vm/exceptions.S b/test/vmapi/exceptions.S
similarity index 100%
rename from test/vm/exceptions.S
rename to test/vmapi/exceptions.S
diff --git a/test/vm/gicv3.c b/test/vmapi/gicv3.c
similarity index 100%
rename from test/vm/gicv3.c
rename to test/vmapi/gicv3.c
diff --git a/test/vm/interrupts.c b/test/vmapi/interrupts.c
similarity index 100%
rename from test/vm/interrupts.c
rename to test/vmapi/interrupts.c
diff --git a/test/vm/interrupts.h b/test/vmapi/interrupts.h
similarity index 100%
rename from test/vm/interrupts.h
rename to test/vmapi/interrupts.h
diff --git a/test/vm/primary_only.c b/test/vmapi/primary_only.c
similarity index 100%
rename from test/vm/primary_only.c
rename to test/vmapi/primary_only.c
diff --git a/test/vm/primary_with_secondaries.c b/test/vmapi/primary_with_secondaries.c
similarity index 100%
rename from test/vm/primary_with_secondaries.c
rename to test/vmapi/primary_with_secondaries.c
diff --git a/test/vm/secondaries/BUILD.gn b/test/vmapi/secondaries/BUILD.gn
similarity index 87%
rename from test/vm/secondaries/BUILD.gn
rename to test/vmapi/secondaries/BUILD.gn
index cd0ad69..577fe93 100644
--- a/test/vm/secondaries/BUILD.gn
+++ b/test/vmapi/secondaries/BUILD.gn
@@ -22,7 +22,7 @@
]
deps = [
- "//test/vm:secondary_vm",
+ "//test/hftest:hftest_secondary_vm",
]
}
@@ -34,7 +34,7 @@
]
deps = [
- "//test/vm:secondary_vm",
+ "//test/hftest:hftest_secondary_vm",
]
}
@@ -46,6 +46,6 @@
]
deps = [
- "//test/vm:secondary_vm",
+ "//test/hftest:hftest_secondary_vm",
]
}
diff --git a/test/vm/secondaries/echo.c b/test/vmapi/secondaries/echo.c
similarity index 100%
rename from test/vm/secondaries/echo.c
rename to test/vmapi/secondaries/echo.c
diff --git a/test/vm/secondaries/relay_a.c b/test/vmapi/secondaries/relay_a.c
similarity index 100%
rename from test/vm/secondaries/relay_a.c
rename to test/vmapi/secondaries/relay_a.c
diff --git a/test/vm/secondaries/relay_b.c b/test/vmapi/secondaries/relay_b.c
similarity index 100%
rename from test/vm/secondaries/relay_b.c
rename to test/vmapi/secondaries/relay_b.c