SMC whitelist from the manifest.
This works for a small number of SMCs. `smc_whitelist` is a list of the
SMCs a VM is allowed to make. `smc_whitelist_permissive` can be set to
allow SMCs through even if they are not whitelisted (for development and
debug).
Bug: 132421503
Change-Id: I64b243d551da35f7625368a72a5a3980d63752f9
diff --git a/docs/Manifest.md b/docs/Manifest.md
index 4f69076..70a56f4 100644
--- a/docs/Manifest.md
+++ b/docs/Manifest.md
@@ -51,6 +51,11 @@
debug_name = "primary VM";
kernel_filename = "vmlinuz";
ramdisk_filename = "initrd.img";
+
+ smc_whitelist = <
+ 0x04000000
+ 0x3200ffff
+ >;
};
vm2 {
@@ -58,6 +63,8 @@
kernel_filename = "kernel0";
vcpu_count = <2>;
mem_size = <0x100000>;
+
+ smc_whitelist_permissive = <1>;
};
vm3 {
diff --git a/inc/hf/manifest.h b/inc/hf/manifest.h
index 3e9f76f..cfedc61 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -20,6 +20,7 @@
#include "hf/memiter.h"
#include "hf/spci.h"
#include "hf/string.h"
+#include "hf/vm.h"
/**
* Holds information about one of the VMs described in the manifest.
@@ -28,6 +29,7 @@
/* Properties defined for both primary and secondary VMs. */
struct string debug_name;
struct string kernel_filename;
+ struct smc_whitelist smc_whitelist;
union {
/* Properties specific to the primary VM. */
@@ -63,6 +65,7 @@
MANIFEST_ERROR_MALFORMED_STRING_LIST,
MANIFEST_ERROR_MALFORMED_INTEGER,
MANIFEST_ERROR_INTEGER_OVERFLOW,
+ MANIFEST_ERROR_MALFORMED_INTEGER_LIST,
};
enum manifest_return_code manifest_init(struct manifest *manifest,
diff --git a/inc/hf/vm.h b/inc/hf/vm.h
index 4abff00..7ea1e12 100644
--- a/inc/hf/vm.h
+++ b/inc/hf/vm.h
@@ -27,6 +27,7 @@
#include "vmapi/hf/spci.h"
+#define MAX_SMCS 32
#define LOG_BUFFER_SIZE 256
enum mailbox_state {
@@ -77,8 +78,16 @@
struct list_entry ready_list;
};
+struct smc_whitelist {
+ uint32_t smcs[MAX_SMCS];
+ uint16_t smc_count;
+ bool permissive;
+};
+
struct vm {
spci_vm_id_t id;
+ struct smc_whitelist smc_whitelist;
+
/** See api.c for the partial ordering on locks. */
struct spinlock lock;
spci_vcpu_count_t vcpu_count;
@@ -86,7 +95,7 @@
struct mm_ptable ptable;
struct mailbox mailbox;
char log_buffer[LOG_BUFFER_SIZE];
- size_t log_buffer_length;
+ uint16_t log_buffer_length;
/** Wait entries to be used when waiting on other VM mailboxes. */
struct wait_entry wait_entries[MAX_VMS];
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index acbe562..00ba80b 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -256,51 +256,58 @@
write_msr(hcr_el2, hcr_el2);
}
-static bool smc_check_client_privileges(const struct vcpu *vcpu)
+/**
+ * Checks whether to block an SMC being forwarded from a VM.
+ */
+static bool smc_is_blocked(const struct vm *vm, uint32_t func)
{
- (void)vcpu; /*UNUSED*/
+ bool block_by_default = !vm->smc_whitelist.permissive;
- /*
- * TODO(b/132421503): Check for privileges based on manifest.
- * Currently returns false, which maintains existing behavior.
- */
+ for (size_t i = 0; i < vm->smc_whitelist.smc_count; ++i) {
+ if (func == vm->smc_whitelist.smcs[i]) {
+ return false;
+ }
+ }
- return false;
+ dlog("SMC %#010x attempted from VM %d, blocked=%d\n", func, vm->id,
+ block_by_default);
+
+ /* Access is still allowed in permissive mode. */
+ return block_by_default;
}
/**
- * Applies SMC access control according to manifest.
- * Forwards the call if access is granted.
- * Returns true if call is forwarded.
+ * Applies SMC access control according to manifest and forwards the call if
+ * access is granted.
*/
-static bool smc_forwarder(const struct vcpu *vcpu, struct smc_result *ret)
+static void smc_forwarder(const struct vcpu *vcpu, struct smc_result *ret)
{
uint32_t func = vcpu->regs.r[0];
- /* TODO(b/132421503): obtain vmid according to new scheme. */
uint32_t client_id = vcpu->vm->id;
+ uintreg_t arg7;
+
+ if (smc_is_blocked(vcpu->vm, func)) {
+ ret->res0 = SMCCC_ERROR_UNKNOWN;
+ return;
+ }
+
/*
* Set the Client ID but keep the existing Secure OS ID and anything
* else (currently unspecified) that the client may have passed in the
* upper bits.
*/
- uintreg_t arg7 = client_id | (vcpu->regs.r[7] & ~CLIENT_ID_MASK);
+ arg7 = client_id | (vcpu->regs.r[7] & ~CLIENT_ID_MASK);
+ *ret = smc_forward(func, vcpu->regs.r[1], vcpu->regs.r[2],
+ vcpu->regs.r[3], vcpu->regs.r[4], vcpu->regs.r[5],
+ vcpu->regs.r[6], arg7);
- if (smc_check_client_privileges(vcpu)) {
- *ret = smc_forward(func, vcpu->regs.r[1], vcpu->regs.r[2],
- vcpu->regs.r[3], vcpu->regs.r[4],
- vcpu->regs.r[5], vcpu->regs.r[6], arg7);
- /*
- * Preserve the value passed by the caller, rather than the
- * client_id we generated. Note that this would also overwrite
- * any return value that may be in x7, but the SMCs that we are
- * forwarding are legacy calls from before SMCCC 1.2 so won't
- * have more than 4 return values anyway.
- */
- ret->res7 = vcpu->regs.r[7];
- return true;
- }
-
- return false;
+ /*
+ * Preserve the value passed by the caller, rather than the client_id we
+ * generated. Note that this would also overwrite any return value that
+ * may be in x7, but the SMCs that we are forwarding are legacy calls
+ * from before SMCCC 1.2 so won't have more than 4 return values anyway.
+ */
+ ret->res7 = vcpu->regs.r[7];
}
static bool spci_handler(struct spci_value *args, struct vcpu **next)
@@ -362,25 +369,23 @@
/**
* Processes SMC instruction calls.
*/
-static bool smc_handler(struct vcpu *vcpu, struct smc_result *ret,
+static void smc_handler(struct vcpu *vcpu, struct smc_result *ret,
struct vcpu **next)
{
uint32_t func = vcpu->regs.r[0];
if (psci_handler(vcpu, func, vcpu->regs.r[1], vcpu->regs.r[2],
vcpu->regs.r[3], &ret->res0, next)) {
- /* SMC PSCI calls are processed by the PSCI handler. */
- return true;
+ return;
}
switch (func & ~SMCCC_CONVENTION_MASK) {
case HF_DEBUG_LOG:
- api_debug_log(vcpu->regs.r[1], vcpu);
- return true;
+ ret->res0 = api_debug_log(vcpu->regs.r[1], vcpu);
+ return;
}
- /* Remaining SMC calls need to be forwarded. */
- return smc_forwarder(vcpu, ret);
+ smc_forwarder(vcpu, ret);
}
struct vcpu *hvc_handler(struct vcpu *vcpu)
@@ -583,17 +588,13 @@
case 0x17: /* EC = 010111, SMC instruction. */ {
uintreg_t smc_pc = vcpu->regs.pc;
+ struct vcpu *next = NULL;
struct smc_result ret = {.res4 = vcpu->regs.r[4],
.res5 = vcpu->regs.r[5],
.res6 = vcpu->regs.r[6],
.res7 = vcpu->regs.r[7]};
- struct vcpu *next = NULL;
- if (!smc_handler(vcpu, &ret, &next)) {
- /* TODO(b/132421503): handle SMC forward rejection */
- dlog("Unsupported SMC call: %#x\n", vcpu->regs.r[0]);
- ret.res0 = SMCCC_ERROR_UNKNOWN;
- }
+ smc_handler(vcpu, &ret, &next);
/* Skip the SMC instruction. */
vcpu->regs.pc = smc_pc + GET_NEXT_PC_INC(esr);
diff --git a/src/load.c b/src/load.c
index 8df4fe2..5c7fa2a 100644
--- a/src/load.c
+++ b/src/load.c
@@ -92,10 +92,21 @@
}
/**
+ * Performs VM loading activities that are common between the primary and
+ * secondaries.
+ */
+static bool load_common(const struct manifest_vm *manifest_vm, struct vm *vm)
+{
+ vm->smc_whitelist = manifest_vm->smc_whitelist;
+
+ return true;
+}
+
+/**
* Loads the primary VM.
*/
static bool load_primary(struct mm_stage1_locked stage1_locked,
- const struct manifest *manifest,
+ const struct manifest_vm *manifest_vm,
const struct memiter *cpio,
const struct boot_params *params, struct mpool *ppool)
{
@@ -110,8 +121,8 @@
*/
paddr_t primary_end = pa_add(primary_begin, 0x8000000);
- if (!load_kernel(stage1_locked, primary_begin, primary_end,
- &manifest->vm[HF_PRIMARY_VM_INDEX], cpio, ppool)) {
+ if (!load_kernel(stage1_locked, primary_begin, primary_end, manifest_vm,
+ cpio, ppool)) {
dlog("Unable to load primary kernel.");
return false;
}
@@ -126,6 +137,10 @@
return false;
}
+ if (!load_common(manifest_vm, vm)) {
+ return false;
+ }
+
/*
* Map 1TB of address space as device memory to, most likely, make all
* devices available to the primary VM.
@@ -186,6 +201,10 @@
return false;
}
+ if (!load_common(manifest_vm, vm)) {
+ return false;
+ }
+
/* Grant the VM access to the memory. */
if (!mm_vm_identity_map(&vm->ptable, mem_begin, mem_end,
MM_MODE_R | MM_MODE_W | MM_MODE_X,
@@ -292,7 +311,8 @@
struct mem_range mem_ranges_available[MAX_MEM_RANGES];
size_t i;
- if (!load_primary(stage1_locked, manifest, cpio, params, ppool)) {
+ if (!load_primary(stage1_locked, &manifest->vm[HF_PRIMARY_VM_INDEX],
+ cpio, params, ppool)) {
dlog("Unable to load primary VM.\n");
return false;
}
diff --git a/src/manifest.c b/src/manifest.c
index 222716f..1933d10 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -18,6 +18,7 @@
#include "hf/addr.h"
#include "hf/check.h"
+#include "hf/dlog.h"
#include "hf/fdt.h"
#include "hf/static_assert.h"
#include "hf/std.h"
@@ -53,6 +54,24 @@
return ptr;
}
+/**
+ * Read a boolean property: true if present; false if not. The value of the
+ * property is ignored.
+ *
+ * This is the convention used by Linux but beware of things like the following
+ * that will actually be considered as `true`.
+ *
+ * true-property0 = <0>;
+ * true-property1 = "false";
+ */
+static bool read_bool(const struct fdt_node *node, const char *property)
+{
+ const char *data;
+ uint32_t size;
+
+ return fdt_read_property(node, property, &data, &size);
+}
+
static enum manifest_return_code read_string(const struct fdt_node *node,
const char *property,
struct string *out)
@@ -121,6 +140,30 @@
return MANIFEST_SUCCESS;
}
+struct uint32list_iter {
+ struct memiter mem_it;
+};
+
+static enum manifest_return_code read_optional_uint32list(
+ const struct fdt_node *node, const char *property,
+ struct uint32list_iter *out)
+{
+ const char *data;
+ uint32_t size;
+
+ if (!fdt_read_property(node, property, &data, &size)) {
+ memiter_init(&out->mem_it, NULL, 0);
+ return MANIFEST_SUCCESS;
+ }
+
+ if ((size % sizeof(uint32_t)) != 0) {
+ return MANIFEST_ERROR_MALFORMED_INTEGER_LIST;
+ }
+
+ memiter_init(&out->mem_it, data, size);
+ return MANIFEST_SUCCESS;
+}
+
/**
* Represents the value of property whose type is a list of strings. These are
* encoded as one contiguous byte buffer with NULL-separated entries.
@@ -152,6 +195,26 @@
return MANIFEST_SUCCESS;
}
+static bool uint32list_has_next(const struct uint32list_iter *list)
+{
+ return memiter_size(&list->mem_it) > 0;
+}
+
+static uint32_t uint32list_get_next(struct uint32list_iter *list)
+{
+ const char *mem_base = memiter_base(&list->mem_it);
+ uint64_t num;
+
+ CHECK(uint32list_has_next(list));
+
+ if (!fdt_parse_number(mem_base, sizeof(uint32_t), &num)) {
+ return MANIFEST_ERROR_MALFORMED_INTEGER;
+ }
+
+ memiter_advance(&list->mem_it, sizeof(uint32_t));
+ return num;
+}
+
static bool stringlist_has_next(const struct stringlist_iter *list)
{
return memiter_size(&list->mem_it) > 0;
@@ -206,9 +269,26 @@
struct manifest_vm *vm,
spci_vm_id_t vm_id)
{
+ struct uint32list_iter smcs;
+
TRY(read_string(node, "debug_name", &vm->debug_name));
TRY(read_optional_string(node, "kernel_filename",
&vm->kernel_filename));
+
+ TRY(read_optional_uint32list(node, "smc_whitelist", &smcs));
+ while (uint32list_has_next(&smcs) &&
+ vm->smc_whitelist.smc_count < MAX_SMCS) {
+ vm->smc_whitelist.smcs[vm->smc_whitelist.smc_count++] =
+ uint32list_get_next(&smcs);
+ }
+
+ if (uint32list_has_next(&smcs)) {
+ dlog("%s SMC whitelist too long.\n", vm->debug_name);
+ }
+
+ vm->smc_whitelist.permissive =
+ read_bool(node, "smc_whitelist_permissive");
+
if (vm_id == HF_PRIMARY_VM_ID) {
TRY(read_optional_string(node, "ramdisk_filename",
&vm->primary.ramdisk_filename));
@@ -314,6 +394,8 @@
return "Malformed integer property";
case MANIFEST_ERROR_INTEGER_OVERFLOW:
return "Integer overflow";
+ case MANIFEST_ERROR_MALFORMED_INTEGER_LIST:
+ return "Malformed integer list property";
}
panic("Unexpected manifest return code.");
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 902cf21..ec38a56 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -16,6 +16,7 @@
#include <array>
#include <cstdio>
+#include <span>
#include <sstream>
#include <gmock/gmock.h>
@@ -26,7 +27,9 @@
namespace
{
+using ::testing::ElementsAre;
using ::testing::Eq;
+using ::testing::IsEmpty;
using ::testing::NotNull;
template <typename T>
@@ -120,7 +123,7 @@
StartChild("/");
}
- std::vector<char> Build()
+ std::vector<char> Build(bool dump = false)
{
const char *program = "./build/image/dtc.py";
const char *dtc_args[] = {program, "compile", NULL};
@@ -129,10 +132,19 @@
/* Finish root node. */
EndChild();
+ if (dump) {
+ Dump();
+ }
+
exec(program, dtc_args, dts_.str(), &dtc_stdout);
return dtc_stdout;
}
+ void Dump()
+ {
+ std::cerr << dts_.str() << std::endl;
+ }
+
ManifestDtBuilder &StartChild(const std::string_view &name)
{
dts_ << name << " {" << std::endl;
@@ -166,16 +178,33 @@
return StringProperty("ramdisk_filename", value);
}
- ManifestDtBuilder &VcpuCount(uint64_t value)
+ ManifestDtBuilder &VcpuCount(uint32_t value)
{
return IntegerProperty("vcpu_count", value);
}
- ManifestDtBuilder &MemSize(uint64_t value)
+ ManifestDtBuilder &MemSize(uint32_t value)
{
return IntegerProperty("mem_size", value);
}
+ ManifestDtBuilder &SmcWhitelist(const std::vector<uint32_t> &value)
+ {
+ return IntegerListProperty("smc_whitelist", value);
+ }
+
+ ManifestDtBuilder &SmcWhitelistPermissive()
+ {
+ return BooleanProperty("smc_whitelist_permissive");
+ }
+
+ ManifestDtBuilder &Property(const std::string_view &name,
+ const std::string_view &value)
+ {
+ dts_ << name << " = " << value << ";" << std::endl;
+ return *this;
+ }
+
private:
ManifestDtBuilder &StringProperty(const std::string_view &name,
const std::string_view &value)
@@ -204,12 +233,29 @@
}
ManifestDtBuilder &IntegerProperty(const std::string_view &name,
- uint64_t value)
+ uint32_t value)
{
dts_ << name << " = <" << value << ">;" << std::endl;
return *this;
}
+ ManifestDtBuilder &IntegerListProperty(
+ const std::string_view &name,
+ const std::vector<uint32_t> &value)
+ {
+ dts_ << name << " = < ";
+ for (const uint32_t entry : value) {
+ dts_ << entry << " ";
+ }
+ dts_ << ">;" << std::endl;
+ return *this;
+ }
+
+ ManifestDtBuilder &BooleanProperty(const std::string_view &name)
+ {
+ return IntegerProperty(name, 1);
+ }
+
std::stringstream dts_;
};
@@ -365,7 +411,7 @@
ASSERT_EQ(manifest_init(&m, &fdt_root), MANIFEST_ERROR_RESERVED_VM_ID);
}
-static std::vector<char> gen_vcpu_count_limit_dtb(uint64_t vcpu_count)
+static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
{
/* clang-format off */
return ManifestDtBuilder()
@@ -426,6 +472,51 @@
ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
}
+TEST(manifest, valid_true_booleans)
+{
+ struct manifest m;
+ struct manifest_vm *vm;
+ struct fdt_node fdt_root;
+
+ /* clang-format off */
+ std::vector<char> dtb = ManifestDtBuilder()
+ .StartChild("hypervisor")
+ .Compatible()
+ .StartChild("vm1")
+ .DebugName("primary_vm")
+ .Property("smc_whitelist_permissive", "\"false\"")
+ .EndChild()
+ .StartChild("vm2")
+ .DebugName("first_secondary_vm")
+ .VcpuCount(42)
+ .MemSize(12345)
+ .Property("smc_whitelist_permissive", "<0>")
+ .EndChild()
+ .StartChild("vm3")
+ .DebugName("second_secondary_vm")
+ .VcpuCount(43)
+ .MemSize(0x12345)
+ .Property("smc_whitelist_permissive", "\"true\"")
+ .EndChild()
+ .EndChild()
+ .Build();
+ /* clang-format on */
+
+ ASSERT_TRUE(get_fdt_root(dtb, &fdt_root));
+
+ ASSERT_EQ(manifest_init(&m, &fdt_root), MANIFEST_SUCCESS);
+ ASSERT_EQ(m.vm_count, 3);
+
+ vm = &m.vm[0];
+ ASSERT_TRUE(vm->smc_whitelist.permissive);
+
+ vm = &m.vm[1];
+ ASSERT_TRUE(vm->smc_whitelist.permissive);
+
+ vm = &m.vm[2];
+ ASSERT_TRUE(vm->smc_whitelist.permissive);
+}
+
TEST(manifest, valid)
{
struct manifest m;
@@ -440,6 +531,7 @@
.DebugName("primary_vm")
.KernelFilename("primary_kernel")
.RamdiskFilename("primary_ramdisk")
+ .SmcWhitelist({0x32000000, 0x33001111})
.EndChild()
.StartChild("vm3")
.DebugName("second_secondary_vm")
@@ -451,6 +543,8 @@
.DebugName("first_secondary_vm")
.VcpuCount(42)
.MemSize(12345)
+ .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
+ .SmcWhitelistPermissive()
.EndChild()
.EndChild()
.Build();
@@ -466,12 +560,20 @@
ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
"primary_ramdisk");
+ ASSERT_THAT(
+ std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
+ ElementsAre(0x32000000, 0x33001111));
+ ASSERT_FALSE(vm->smc_whitelist.permissive);
vm = &m.vm[1];
ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
ASSERT_STREQ(string_data(&vm->kernel_filename), "");
ASSERT_EQ(vm->secondary.vcpu_count, 42);
ASSERT_EQ(vm->secondary.mem_size, 12345);
+ ASSERT_THAT(
+ std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
+ ElementsAre(0x04000000, 0x30002222, 0x31445566));
+ ASSERT_TRUE(vm->smc_whitelist.permissive);
vm = &m.vm[2];
ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
@@ -479,6 +581,10 @@
"second_secondary_kernel");
ASSERT_EQ(vm->secondary.vcpu_count, 43);
ASSERT_EQ(vm->secondary.mem_size, 0x12345);
+ ASSERT_THAT(
+ std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
+ IsEmpty());
+ ASSERT_FALSE(vm->smc_whitelist.permissive);
}
} /* namespace */
diff --git a/test/vmapi/arch/aarch64/BUILD.gn b/test/vmapi/arch/aarch64/BUILD.gn
index a43f30a..618fe3a 100644
--- a/test/vmapi/arch/aarch64/BUILD.gn
+++ b/test/vmapi/arch/aarch64/BUILD.gn
@@ -25,8 +25,10 @@
# Tests specific to aarch64.
vm_kernel("aarch64_test_vm") {
testonly = true
+ public_configs = [ "//src/arch/aarch64:config" ]
sources = [
+ "smc_whitelist.c",
"smccc.c",
]
diff --git a/test/vmapi/arch/aarch64/gicv3/BUILD.gn b/test/vmapi/arch/aarch64/gicv3/BUILD.gn
index f3325e0..43a7fea 100644
--- a/test/vmapi/arch/aarch64/gicv3/BUILD.gn
+++ b/test/vmapi/arch/aarch64/gicv3/BUILD.gn
@@ -32,8 +32,8 @@
]
deps = [
- "//src/arch/${plat_arch}:arch",
- "//src/arch/${plat_arch}/hftest:interrupts_gicv3",
+ "//src/arch/aarch64:arch",
+ "//src/arch/aarch64/hftest:interrupts_gicv3",
"//test/hftest:hftest_primary_vm",
]
}
diff --git a/test/vmapi/arch/aarch64/manifest.dts b/test/vmapi/arch/aarch64/manifest.dts
index d77879c..2d56429 100644
--- a/test/vmapi/arch/aarch64/manifest.dts
+++ b/test/vmapi/arch/aarch64/manifest.dts
@@ -23,6 +23,13 @@
vm1 {
debug_name = "aarch64_test";
kernel_filename = "aarch64_test";
+
+ smc_whitelist = <
+ 0x30000001
+ 0x30000002
+ 0x30000003
+ 0x30000004
+ >;
};
};
};
diff --git a/test/vmapi/arch/aarch64/smc_whitelist.c b/test/vmapi/arch/aarch64/smc_whitelist.c
new file mode 100644
index 0000000..de4a7bd
--- /dev/null
+++ b/test/vmapi/arch/aarch64/smc_whitelist.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 The Hafnium Authors.
+ *
+ * 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 "vmapi/hf/call.h"
+
+#include "hftest.h"
+#include "smc.h"
+
+TEST(smc_whitelist, not_whitelisted_unknown)
+{
+ const uint32_t non_whitelisted_ta_call = 0x3000f00d;
+ struct smc_result smc_res = smc_forward(
+ non_whitelisted_ta_call, 0x1111111111111111, 0x2222222222222222,
+ 0x3333333333333333, 0x4444444444444444, 0x5555555555555555,
+ 0x6666666666666666, 0x77777777);
+
+ EXPECT_EQ(smc_res.res0, SMCCC_ERROR_UNKNOWN);
+ EXPECT_EQ(smc_res.res1, 0);
+ EXPECT_EQ(smc_res.res2, 0);
+ EXPECT_EQ(smc_res.res3, 0);
+ EXPECT_EQ(smc_res.res4, UINT64_C(0x4444444444444444));
+ EXPECT_EQ(smc_res.res5, UINT64_C(0x5555555555555555));
+ EXPECT_EQ(smc_res.res6, UINT64_C(0x6666666666666666));
+ EXPECT_EQ(smc_res.res7, UINT64_C(0x77777777));
+}
diff --git a/test/vmapi/arch/aarch64/smccc.c b/test/vmapi/arch/aarch64/smccc.c
index 39bc764..9e3a0a8 100644
--- a/test/vmapi/arch/aarch64/smccc.c
+++ b/test/vmapi/arch/aarch64/smccc.c
@@ -17,30 +17,21 @@
#include "vmapi/hf/call.h"
#include "hftest.h"
+#include "smc.h"
TEST(smccc, hf_debug_log_zero_or_unchanged)
{
- register uint64_t r0 __asm__("x0") = HF_DEBUG_LOG;
- register uint64_t r1 __asm__("x1") = '\n';
- register uint64_t r2 __asm__("x2") = UINT64_C(0x2222222222222222);
- register uint64_t r3 __asm__("x3") = UINT64_C(0x3333333333333333);
- register uint64_t r4 __asm__("x4") = UINT64_C(0x4444444444444444);
- register uint64_t r5 __asm__("x5") = UINT64_C(0x5555555555555555);
- register uint64_t r6 __asm__("x6") = UINT64_C(0x6666666666666666);
- register uint64_t r7 __asm__("x7") = UINT64_C(0x7777777777777777);
+ struct smc_result smc_res =
+ smc_forward(HF_DEBUG_LOG, '\n', 0x2222222222222222,
+ 0x3333333333333333, 0x4444444444444444,
+ 0x5555555555555555, 0x6666666666666666, 0x77777777);
- __asm__ volatile(
- "smc #0"
- : /* Output registers, also used as inputs ('+' constraint). */
- "+r"(r0), "+r"(r1), "+r"(r2), "+r"(r3), "+r"(r4), "+r"(r5),
- "+r"(r6), "+r"(r7));
-
- EXPECT_EQ(r0, 0);
- EXPECT_EQ(r1, 0);
- EXPECT_EQ(r2, 0);
- EXPECT_EQ(r3, 0);
- EXPECT_EQ(r4, UINT64_C(0x4444444444444444));
- EXPECT_EQ(r5, UINT64_C(0x5555555555555555));
- EXPECT_EQ(r6, UINT64_C(0x6666666666666666));
- EXPECT_EQ(r7, UINT64_C(0x7777777777777777));
+ EXPECT_EQ(smc_res.res0, 0);
+ EXPECT_EQ(smc_res.res1, 0);
+ EXPECT_EQ(smc_res.res2, 0);
+ EXPECT_EQ(smc_res.res3, 0);
+ EXPECT_EQ(smc_res.res4, UINT64_C(0x4444444444444444));
+ EXPECT_EQ(smc_res.res5, UINT64_C(0x5555555555555555));
+ EXPECT_EQ(smc_res.res6, UINT64_C(0x6666666666666666));
+ EXPECT_EQ(smc_res.res7, UINT64_C(0x77777777));
}