Pass mapped memory size to secondary VMs on boot in x0.

Bug: 117082339
Change-Id: I851669d79cbae67d0a99dabc026b0919ae4e9ed3
diff --git a/src/load.c b/src/load.c
index ef033a6..0f71770 100644
--- a/src/load.c
+++ b/src/load.c
@@ -348,7 +348,9 @@
 		dlog("Loaded with %u vcpus, entry at 0x%x\n", cpu,
 		     pa_addr(secondary_mem_begin));
 
-		vm_secondary_start_vcpu(vm, 0, secondary_entry, 0);
+		vm_secondary_start_vcpu(
+			vm, 0, secondary_entry,
+			pa_difference(secondary_mem_begin, secondary_mem_end));
 	}
 
 	/*
diff --git a/test/hftest/hftest_service.c b/test/hftest/hftest_service.c
index c728e27..455b86a 100644
--- a/test/hftest/hftest_service.c
+++ b/test/hftest/hftest_service.c
@@ -76,7 +76,7 @@
 	}
 }
 
-noreturn void kmain(void)
+noreturn void kmain(size_t memory_size)
 {
 	struct memiter args;
 	hftest_test_fn service;
@@ -111,6 +111,7 @@
 	ctx->abort = abort;
 	ctx->send = (struct spci_message *)send;
 	ctx->recv = (struct spci_message *)recv;
+	ctx->memory_size = memory_size;
 
 	/* Pause so the next time cycles are given the service will be run. */
 	hf_vcpu_yield();
diff --git a/test/hftest/inc/hftest.h b/test/hftest/inc/hftest.h
index 145c2ed..d22cadf 100644
--- a/test/hftest/inc/hftest.h
+++ b/test/hftest/inc/hftest.h
@@ -72,6 +72,7 @@
 
 #define SERVICE_SEND_BUFFER() HFTEST_SERVICE_SEND_BUFFER()
 #define SERVICE_RECV_BUFFER() HFTEST_SERVICE_RECV_BUFFER()
+#define SERVICE_MEMORY_SIZE() HFTEST_SERVICE_MEMORY_SIZE()
 
 /*
  * This must be used exactly once in a test image to signal to the linker that
diff --git a/test/hftest/inc/hftest_impl.h b/test/hftest/inc/hftest_impl.h
index 346e496..13b49f1 100644
--- a/test/hftest/inc/hftest_impl.h
+++ b/test/hftest/inc/hftest_impl.h
@@ -136,6 +136,7 @@
 	/* These are used in services. */
 	struct spci_message *send;
 	struct spci_message *recv;
+	size_t memory_size;
 };
 
 struct hftest_context *hftest_get_context(void);
@@ -296,5 +297,6 @@
 
 #define HFTEST_SERVICE_SEND_BUFFER() hftest_get_context()->send
 #define HFTEST_SERVICE_RECV_BUFFER() hftest_get_context()->recv
+#define HFTEST_SERVICE_MEMORY_SIZE() hftest_get_context()->memory_size
 
 void hftest_register(struct hftest_test test);
diff --git a/test/vmapi/primary_with_secondaries/BUILD.gn b/test/vmapi/primary_with_secondaries/BUILD.gn
index 34f8857..868487e 100644
--- a/test/vmapi/primary_with_secondaries/BUILD.gn
+++ b/test/vmapi/primary_with_secondaries/BUILD.gn
@@ -25,6 +25,7 @@
 
   sources = [
     "abort.c",
+    "boot.c",
     "interrupts.c",
     "mailbox.c",
     "memory_sharing.c",
diff --git a/test/vmapi/primary_with_secondaries/boot.c b/test/vmapi/primary_with_secondaries/boot.c
new file mode 100644
index 0000000..d6aa553
--- /dev/null
+++ b/test/vmapi/primary_with_secondaries/boot.c
@@ -0,0 +1,65 @@
+/*
+ * 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 "hf/dlog.h"
+
+#include "vmapi/hf/call.h"
+
+#include "hftest.h"
+#include "primary_with_secondary.h"
+#include "util.h"
+
+/**
+ * The VM gets its memory size on boot, and can access it all.
+ */
+TEST(boot, memory_size)
+{
+	struct hf_vcpu_run_return run_res;
+	struct mailbox_buffers mb = set_up_mailbox();
+
+	SERVICE_SELECT(SERVICE_VM0, "boot_memory", mb.send);
+
+	run_res = hf_vcpu_run(SERVICE_VM0, 0);
+	EXPECT_EQ(run_res.code, HF_VCPU_RUN_YIELD);
+}
+
+/**
+ * Accessing memory outside the given range aborts the VM.
+ */
+TEST(boot, beyond_memory_size)
+{
+	struct hf_vcpu_run_return run_res;
+	struct mailbox_buffers mb = set_up_mailbox();
+
+	SERVICE_SELECT(SERVICE_VM0, "boot_memory_overrun", mb.send);
+
+	run_res = hf_vcpu_run(SERVICE_VM0, 0);
+	EXPECT_EQ(run_res.code, HF_VCPU_RUN_ABORTED);
+}
+
+/**
+ * Accessing memory before the start of the image aborts the VM.
+ */
+TEST(boot, memory_before_image)
+{
+	struct hf_vcpu_run_return run_res;
+	struct mailbox_buffers mb = set_up_mailbox();
+
+	SERVICE_SELECT(SERVICE_VM0, "boot_memory_underrun", mb.send);
+
+	run_res = hf_vcpu_run(SERVICE_VM0, 0);
+	EXPECT_EQ(run_res.code, HF_VCPU_RUN_ABORTED);
+}
diff --git a/test/vmapi/primary_with_secondaries/services/BUILD.gn b/test/vmapi/primary_with_secondaries/services/BUILD.gn
index 6b15dc7..377ac03 100644
--- a/test/vmapi/primary_with_secondaries/services/BUILD.gn
+++ b/test/vmapi/primary_with_secondaries/services/BUILD.gn
@@ -72,6 +72,16 @@
   ]
 }
 
+# Services related to the boot process for VMs.
+source_set("boot") {
+  testonly = true
+  public_configs = [ "//test/hftest:hftest_config" ]
+
+  sources = [
+    "boot.c",
+  ]
+}
+
 # Service that can be interrupted.
 source_set("interruptible") {
   testonly = true
@@ -145,6 +155,7 @@
 
   deps = [
     ":abort",
+    ":boot",
     ":check_state",
     ":echo",
     ":echo_with_notification",
diff --git a/test/vmapi/primary_with_secondaries/services/boot.c b/test/vmapi/primary_with_secondaries/services/boot.c
new file mode 100644
index 0000000..965c5bb
--- /dev/null
+++ b/test/vmapi/primary_with_secondaries/services/boot.c
@@ -0,0 +1,72 @@
+/*
+ * 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 "hf/mm.h"
+#include "hf/std.h"
+
+#include "vmapi/hf/call.h"
+
+#include "hftest.h"
+
+/*
+ * This must match the size specified for services0 in
+ * //test/vmapi/primary_with_secondaries:primary_with_secondaries_test.
+ */
+#define SECONDARY_MEMORY_SIZE 1048576
+
+extern uint8_t volatile text_begin[];
+
+TEST_SERVICE(boot_memory)
+{
+	uint8_t checksum = 0;
+
+	/* Check that the size passed in by Hafnium is what is expected. */
+	ASSERT_EQ(SERVICE_MEMORY_SIZE(), SECONDARY_MEMORY_SIZE);
+
+	/*
+	 * Check that we can read all memory up to the given size. Calculate a
+	 * basic checksum and check that it is non-zero, as a double-check that
+	 * we are actually reading something.
+	 */
+	for (size_t i = 0; i < SERVICE_MEMORY_SIZE(); ++i) {
+		checksum += text_begin[i];
+	}
+	ASSERT_NE(checksum, 0);
+	dlog("Checksum of all memory is %d\n", checksum);
+
+	hf_vcpu_yield();
+}
+
+TEST_SERVICE(boot_memory_underrun)
+{
+	/*
+	 * Try to read memory below the start of the image. This should result
+	 * in the VM being aborted.
+	 */
+	dlog("Read memory below limit: %d\n", text_begin[-1]);
+	FAIL("Managed to read memory below limit");
+}
+
+TEST_SERVICE(boot_memory_overrun)
+{
+	/*
+	 * Try to read memory above the limit defined by memory_size. This
+	 * should result in the VM being aborted.
+	 */
+	dlog("Read memory above limit: %d\n",
+	     text_begin[SERVICE_MEMORY_SIZE()]);
+	FAIL("Managed to read memory above limit");
+}