Allow projects to define their own build.
To create a new project, add a directory under `project` and pass the
project name to `make`:
mkdir project/my_project
# Describe the build for the project.
PROJECT=my_project make
Projects can be maintained separately from the main repository.
Change-Id: I33a9d7ca801e2fb3dd9795ece44577b3b565e913
diff --git a/src/BUILD.gn b/src/BUILD.gn
index d3d1a34..83621a5 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -13,6 +13,7 @@
# limitations under the License.
import("//build/image/image.gni")
+import("//build/toolchain/platform.gni")
# The hypervisor image.
hypervisor("hafnium") {
@@ -31,9 +32,11 @@
"cpio.c",
"load.c",
"main.c",
+ "plat.c",
]
deps = [
":src_testable",
+ "//project/${project}/${plat_name}",
]
}
@@ -55,7 +58,7 @@
":common",
":fdt",
":memiter",
- "//src/arch/${arch}",
+ "//src/arch/${plat_arch}",
]
if (is_debug) {
@@ -78,7 +81,7 @@
deps = [
":common",
- "//src/arch/${arch}:putchar",
+ "//src/arch/${plat_arch}:putchar",
]
}
diff --git a/src/arch/aarch64/BUILD.gn b/src/arch/aarch64/BUILD.gn
index 1588e18..8909fb8 100644
--- a/src/arch/aarch64/BUILD.gn
+++ b/src/arch/aarch64/BUILD.gn
@@ -20,6 +20,7 @@
"cpu_entry.S",
"exceptions.S",
"hypervisor_entry.S",
+ "plat_entry.S",
"smc.S",
]
@@ -27,7 +28,6 @@
"handler.c",
"mm.c",
"offsets.c",
- "params.c",
]
deps = [
diff --git a/src/arch/aarch64/hypervisor_entry.S b/src/arch/aarch64/hypervisor_entry.S
index 39061d8..468c684 100644
--- a/src/arch/aarch64/hypervisor_entry.S
+++ b/src/arch/aarch64/hypervisor_entry.S
@@ -17,10 +17,8 @@
.section .init.image_entry, "ax"
.global image_entry
image_entry:
- /* Save the FDT to a global variable. */
- adrp x30, fdt_addr
- add x30, x30, :lo12:fdt_addr
- str x0, [x30]
+ /* Interpret the registers passed from the loader. */
+ bl plat_entry
/* Get pointer to first cpu. */
adrp x0, cpus
diff --git a/src/arch/aarch64/params.c b/src/arch/aarch64/params.c
deleted file mode 100644
index ab1400f..0000000
--- a/src/arch/aarch64/params.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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/boot_params.h"
-#include "hf/fdt_handler.h"
-
-/* This is set by entry.S. */
-uintpaddr_t fdt_addr;
-
-/*
- * The following are declared weak so that they can overwritten by platform code
- * if desired.
- */
-#pragma weak plat_get_boot_params
-bool plat_get_boot_params(struct boot_params *p)
-{
- return fdt_get_boot_params(pa_init(fdt_addr), p);
-}
-
-#pragma weak plat_update_boot_params
-bool plat_update_boot_params(struct boot_params_update *p)
-{
- return fdt_patch(pa_init(fdt_addr), p);
-}
diff --git a/src/arch/aarch64/plat_entry.S b/src/arch/aarch64/plat_entry.S
new file mode 100644
index 0000000..75d7dc4
--- /dev/null
+++ b/src/arch/aarch64/plat_entry.S
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+.section .init.image_entry, "ax"
+.global plat_entry
+.weak plat_entry
+plat_entry:
+ /* Do nothing. */
+ ret
diff --git a/src/fdt_handler.c b/src/fdt_handler.c
index c29a0e2..cba2a4e 100644
--- a/src/fdt_handler.c
+++ b/src/fdt_handler.c
@@ -99,34 +99,33 @@
* Finds the memory region where initrd is stored, and updates the fdt node
* cursor to the node called "chosen".
*/
-static bool find_initrd(struct fdt_node *n, struct boot_params *p)
+bool fdt_find_initrd(struct fdt_node *n, paddr_t *begin, paddr_t *end)
{
- uint64_t begin;
- uint64_t end;
+ uint64_t initrd_begin;
+ uint64_t initrd_end;
if (!fdt_find_child(n, "chosen")) {
dlog("Unable to find 'chosen'\n");
return false;
}
- if (!fdt_read_number(n, "linux,initrd-start", &begin)) {
+ if (!fdt_read_number(n, "linux,initrd-start", &initrd_begin)) {
dlog("Unable to read linux,initrd-start\n");
return false;
}
- if (!fdt_read_number(n, "linux,initrd-end", &end)) {
+ if (!fdt_read_number(n, "linux,initrd-end", &initrd_end)) {
dlog("Unable to read linux,initrd-end\n");
return false;
}
- p->initrd_begin = pa_init(begin);
- p->initrd_end = pa_init(end);
+ *begin = pa_init(initrd_begin);
+ *end = pa_init(initrd_end);
return true;
}
-static void find_memory_ranges(const struct fdt_node *root,
- struct boot_params *p)
+void fdt_find_memory_ranges(const struct fdt_node *root, struct boot_params *p)
{
struct fdt_node n = *root;
const char *name;
@@ -193,23 +192,21 @@
/* TODO: Check for "reserved-memory" nodes. */
}
-bool fdt_get_boot_params(paddr_t fdt_addr, struct boot_params *p)
+struct fdt_header *fdt_map(paddr_t fdt_addr, struct fdt_node *n)
{
struct fdt_header *fdt;
- struct fdt_node n;
- bool ret = false;
/* Map the fdt header in. */
fdt = mm_identity_map(fdt_addr, pa_add(fdt_addr, fdt_header_size()),
MM_MODE_R);
if (!fdt) {
dlog("Unable to map FDT header.\n");
- goto err_unmap_fdt_header;
+ return NULL;
}
- if (!fdt_root_node(&n, fdt)) {
+ if (!fdt_root_node(n, fdt)) {
dlog("FDT failed validation.\n");
- goto err_unmap_fdt_header;
+ goto fail;
}
/* Map the rest of the fdt in. */
@@ -217,31 +214,20 @@
MM_MODE_R);
if (!fdt) {
dlog("Unable to map full FDT.\n");
- goto err_unmap_fdt_header;
+ goto fail;
}
- if (!fdt_find_child(&n, "")) {
- dlog("Unable to find FDT root node.\n");
- goto out_unmap_fdt;
- }
+ return fdt;
- p->mem_ranges_count = 0;
- find_memory_ranges(&n, p);
-
- if (!find_initrd(&n, p)) {
- goto out_unmap_fdt;
- }
-
- p->kernel_arg = (uintreg_t)fdt;
- ret = true;
-
-out_unmap_fdt:
- mm_unmap(fdt_addr, pa_add(fdt_addr, fdt_total_size(fdt)), 0);
- return ret;
-
-err_unmap_fdt_header:
+fail:
mm_unmap(fdt_addr, pa_add(fdt_addr, fdt_header_size()), 0);
- return false;
+ return NULL;
+}
+
+bool fdt_unmap(struct fdt_header *fdt)
+{
+ paddr_t fdt_addr = pa_from_va(va_from_ptr(fdt));
+ return mm_unmap(fdt_addr, pa_add(fdt_addr, fdt_total_size(fdt)), 0);
}
bool fdt_patch(paddr_t fdt_addr, struct boot_params_update *p)
diff --git a/src/fdt_handler_test.cc b/src/fdt_handler_test.cc
index 9556ede..c544454 100644
--- a/src/fdt_handler_test.cc
+++ b/src/fdt_handler_test.cc
@@ -28,6 +28,7 @@
namespace
{
using ::testing::Eq;
+using ::testing::NotNull;
constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 10;
@@ -92,15 +93,22 @@
0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2c,
0x69, 0x6e, 0x69, 0x74, 0x72, 0x64, 0x2d, 0x65, 0x6e, 0x64, 0x00};
-TEST(fdt, get_boot_params)
+TEST(fdt, find_memory_ranges)
{
std::unique_ptr<uint8_t[]> test_heap(new uint8_t[TEST_HEAP_SIZE]);
halloc_init((size_t)test_heap.get(), TEST_HEAP_SIZE);
ASSERT_TRUE(mm_init());
+ struct fdt_header *fdt;
+ struct fdt_node n;
struct boot_params params = {};
- EXPECT_TRUE(
- fdt_get_boot_params(pa_init((uintpaddr_t)&test_dtb), ¶ms));
+
+ fdt = fdt_map(pa_init((uintpaddr_t)&test_dtb), &n);
+ ASSERT_THAT(fdt, NotNull());
+ ASSERT_TRUE(fdt_find_child(&n, ""));
+ fdt_find_memory_ranges(&n, ¶ms);
+ ASSERT_TRUE(fdt_unmap(fdt));
+
EXPECT_THAT(params.mem_ranges_count, Eq(3));
EXPECT_THAT(pa_addr(params.mem_ranges[0].begin), Eq(0x00000000));
EXPECT_THAT(pa_addr(params.mem_ranges[0].end), Eq(0x20000000));
diff --git a/src/layout.c b/src/layout.c
index 68b645e..003a8ab 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -71,6 +71,42 @@
}
/**
+ * Get the address the .initrd section begins at.
+ */
+paddr_t layout_initrd_begin(void)
+{
+ extern uint8_t initrd_begin[];
+ return pa_init((uintpaddr_t)initrd_begin);
+}
+
+/**
+ * Get the address the .initrd section ends at.
+ */
+paddr_t layout_initrd_end(void)
+{
+ extern uint8_t initrd_end[];
+ return pa_init((uintpaddr_t)initrd_end);
+}
+
+/**
+ * Get the address the .fdt section begins at.
+ */
+paddr_t layout_fdt_begin(void)
+{
+ extern uint8_t fdt_begin[];
+ return pa_init((uintpaddr_t)fdt_begin);
+}
+
+/**
+ * Get the address the .fdt section ends at.
+ */
+paddr_t layout_fdt_end(void)
+{
+ extern uint8_t fdt_end[];
+ return pa_init((uintpaddr_t)fdt_end);
+}
+
+/**
* Get the address the loaded image ends at.
*/
paddr_t layout_bin_end(void)
diff --git a/src/plat.c b/src/plat.c
new file mode 100644
index 0000000..c6c1018
--- /dev/null
+++ b/src/plat.c
@@ -0,0 +1,112 @@
+/*
+ * 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/boot_params.h"
+#include "hf/dlog.h"
+#include "hf/fdt_handler.h"
+#include "hf/layout.h"
+
+/**
+ * Default implementation assumes the FDT has been linked into the image.
+ *
+ * This can be overridden e.g. to provide a fixed address or an address passed
+ * by the loader.
+ */
+#pragma weak plat_get_fdt_addr
+paddr_t plat_get_fdt_addr(void)
+{
+ return layout_fdt_begin();
+}
+
+/**
+ * Default implementation assumes the initrd has been linked into the image.
+ *
+ * This can be overridden e.g. to provide a fixed address or an address passed
+ * by the loader.
+ */
+#pragma weak plat_get_initrd_range
+void plat_get_initrd_range(paddr_t *begin, paddr_t *end)
+{
+ *begin = layout_initrd_begin();
+ *end = layout_initrd_end();
+}
+
+/**
+ * Default implementation assumes the FDT address is passed to the kernel.
+ *
+ * TODO: make this part of the VM configuration as secondary VMs will also need
+ * to take arguments.
+ */
+#pragma weak plat_get_kernel_arg
+uintreg_t plat_get_kernel_arg(void)
+{
+ return (uintreg_t)pa_addr(plat_get_fdt_addr());
+}
+
+/**
+ * Default implementation extracts the boot parameters from the FDT but the
+ * initrd is provided separately.
+ */
+#pragma weak plat_get_boot_params
+bool plat_get_boot_params(struct boot_params *p)
+{
+ struct fdt_header *fdt;
+ struct fdt_node n;
+ bool ret = false;
+
+ plat_get_initrd_range(&p->initrd_begin, &p->initrd_end);
+ p->kernel_arg = plat_get_kernel_arg();
+
+ /* Get the memory map from the FDT. */
+ fdt = fdt_map(plat_get_fdt_addr(), &n);
+ if (!fdt) {
+ return false;
+ }
+
+ if (!fdt_find_child(&n, "")) {
+ dlog("Unable to find FDT root node.\n");
+ goto out_unmap_fdt;
+ }
+
+ p->mem_ranges_count = 0;
+ fdt_find_memory_ranges(&n, p);
+
+ ret = true;
+
+out_unmap_fdt:
+ if (!fdt_unmap(fdt)) {
+ dlog("Unable to unmap fdt.");
+ return false;
+ }
+
+ return ret;
+}
+
+/**
+ * Default implementation updates the FDT which is the argument passed to the
+ * primary VM's kernel.
+ *
+ * TODO: in future, each VM will declare whether it expects an argument passed
+ * and that will be static data e.g. it will provide its own FDT so there will
+ * be no FDT modification. This is done because each VM has a very different
+ * view of the system and we don't want to force VMs to require loader code when
+ * another loader can load the data for it.
+ */
+#pragma weak plat_update_boot_params
+bool plat_update_boot_params(struct boot_params_update *p)
+{
+ return fdt_patch(plat_get_fdt_addr(), p);
+}