Adding a unit test for fdt_get_boot_params, and fakes to support it.

Bug: 114733240
Change-Id: I87db5e69e257a9b806fc23020d38a304c045e400
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 82b12c8..1fb87d0 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -5,7 +5,6 @@
     "api.c",
     "cpio.c",
     "cpu.c",
-    "fdt_handler.c",
     "load.c",
     "main.c",
     "mm.c",
@@ -15,6 +14,7 @@
   deps = [
     ":common",
     ":fdt",
+    ":fdt_handler",
     ":memiter",
   ]
 
@@ -53,6 +53,18 @@
   ]
 }
 
+source_set("fdt_handler") {
+  sources = [
+    "fdt_handler.c",
+  ]
+
+  deps = [
+    ":common",
+    ":common_debug",
+    ":fdt",
+  ]
+}
+
 source_set("memiter") {
   sources = [
     "memiter.c",
@@ -63,11 +75,15 @@
   testonly = true
 
   sources = [
+    "fdt_handler_test.cc",
     "fdt_test.cc",
   ]
+  cflags_cc = [ "-Wno-c99-extensions" ]
 
   deps = [
     ":fdt",
+    ":fdt_handler",
+    "mock:mm",
     "//third_party:gtest_main",
   ]
 }
diff --git a/src/arch/mock/inc/hf/arch/mm.h b/src/arch/mock/inc/hf/arch/mm.h
new file mode 100644
index 0000000..676b53f
--- /dev/null
+++ b/src/arch/mock/inc/hf/arch/mm.h
@@ -0,0 +1,135 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "hf/addr.h"
+
+/* A page table entry. */
+typedef uint64_t pte_t;
+
+#define PAGE_LEVEL_BITS 9
+
+/**
+ * Returns the encoding of a page table entry that isn't present.
+ */
+static inline pte_t arch_mm_absent_pte(int level)
+{
+	return 0;
+}
+
+/**
+ * Converts a physical address to a table PTE.
+ *
+ * The spec says that 'Table descriptors for stage 2 translations do not
+ * include any attribute field', so we don't take any attributes as arguments.
+ */
+static inline pte_t arch_mm_table_pte(int level, paddr_t pa)
+{
+	/* This is the same for all levels on aarch64. */
+	(void)level;
+	return pa_addr(pa) | 0x3;
+}
+
+/**
+ * Converts a physical address to a block PTE.
+ *
+ * The level must allow block entries.
+ */
+static inline pte_t arch_mm_block_pte(int level, paddr_t pa, uint64_t attrs)
+{
+	pte_t pte = pa_addr(pa) | attrs;
+	if (level == 0) {
+		pte |= 0x2;
+	}
+	return pte;
+}
+
+/**
+ * Specifies whether block mappings are acceptable at the given level.
+ *
+ * Level 0 must allow block entries.
+ */
+static inline bool arch_mm_is_block_allowed(int level)
+{
+	return level <= 2;
+}
+
+/**
+ * Determines if the given pte is present, i.e., if it points to another table,
+ * to a page, or a block of pages.
+ */
+static inline bool arch_mm_pte_is_present(pte_t pte, int level)
+{
+	return (pte & 0x1) != 0;
+}
+
+/**
+ * Determines if the given pte references another table.
+ */
+static inline bool arch_mm_pte_is_table(pte_t pte, int level)
+{
+	return level != 0 && (pte & 0x3) == 0x3;
+}
+
+/**
+ * Determines if the given pte references a block of pages.
+ */
+static inline bool arch_mm_pte_is_block(pte_t pte, int level)
+{
+	return arch_mm_is_block_allowed(level) &&
+	       (pte & 0x3) == (level == 0 ? 0x3 : 0x1);
+}
+
+/**
+ * Clears the given physical address, i.e., sets the ignored bits (from a page
+ * table perspective) to zero.
+ */
+static inline paddr_t arch_mm_clear_pa(paddr_t pa)
+{
+	return pa_init(0);
+}
+
+/**
+ * Extracts the physical address of the block referred to by the given page
+ * table entry.
+ */
+static inline paddr_t arch_mm_block_from_pte(pte_t pte)
+{
+	return pa_init(pte);
+}
+
+/**
+ * Extracts the physical address of the page table referred to by the given page
+ * table entry.
+ */
+static inline paddr_t arch_mm_table_from_pte(pte_t pte)
+{
+	return pa_init(pte);
+}
+
+/**
+ * Extracts the architecture specific attributes applies to the given page table
+ * entry.
+ */
+static inline uint64_t arch_mm_pte_attrs(pte_t pte)
+{
+	return 0;
+}
+
+/**
+ * Invalidates stage-1 TLB entries referring to the given virtual address range.
+ */
+void arch_mm_invalidate_stage1_range(vaddr_t va_begin, vaddr_t va_end);
+
+/**
+ * Invalidates stage-2 TLB entries referring to the given intermediate physical
+ * address range.
+ */
+void arch_mm_invalidate_stage2_range(ipaddr_t va_begin, ipaddr_t va_end);
+
+void arch_mm_set_vm(uint64_t vmid, paddr_t table);
+
+uint64_t arch_mm_mode_to_attrs(int mode);
+bool arch_mm_init(paddr_t table, bool first);
+int arch_mm_max_level(int mode);
diff --git a/src/fdt_handler.c b/src/fdt_handler.c
index 91a17d8..8fa84c9 100644
--- a/src/fdt_handler.c
+++ b/src/fdt_handler.c
@@ -280,7 +280,7 @@
 
 	/* Patch fdt to reserve primary VM memory. */
 	{
-		size_t tmp = (size_t)&plat_update_boot_params;
+		size_t tmp = (size_t)&fdt_patch;
 		tmp = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
 		fdt_add_mem_reservation(fdt, tmp & ~0xfffff, 0x80000);
 	}
diff --git a/src/fdt_handler_test.cc b/src/fdt_handler_test.cc
new file mode 100644
index 0000000..0e039bb
--- /dev/null
+++ b/src/fdt_handler_test.cc
@@ -0,0 +1,84 @@
+extern "C" {
+#include "hf/fdt_handler.h"
+
+#include "hf/boot_params.h"
+}
+
+#include <gmock/gmock.h>
+
+using ::testing::Eq;
+
+/*
+ * /dts-v1/;
+ *
+ * / {
+ *       #address-cells = <2>;
+ *       #size-cells = <2>;
+ *
+ *       memory@0 {
+ *           device_type = "memory";
+ *           reg = <0x00000000 0x00000000 0x00000000 0x20000000
+ *                  0x00000000 0x30000000 0x00000000 0x00010000>;
+ *       };
+ *       memory@1 {
+ *           device_type = "memory";
+ *           reg = <0x00000000 0x30020000 0x00000000 0x00010000>;
+ *       };
+ *
+ *       chosen {
+ *           linux,initrd-start = <0x00000000>;
+ *           linux,initrd-end = <0x00000000>;
+ *       };
+ * };
+ *
+ * $ dtc --boot-cpu 0 --in-format dts --out-format dtb --out-version 17 test.dts
+ * | xxd -i
+ */
+
+static const uint8_t test_dtb[] = {
+	0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x38,
+	0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
+	0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f,
+	0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
+	0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02,
+	0x00, 0x00, 0x00, 0x01, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x40, 0x30,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07,
+	0x00, 0x00, 0x00, 0x1b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x27,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+	0x00, 0x00, 0x00, 0x01, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x40, 0x31,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07,
+	0x00, 0x00, 0x00, 0x1b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x27,
+	0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
+	0x63, 0x68, 0x6f, 0x73, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+	0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3e,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
+	0x00, 0x00, 0x00, 0x09, 0x23, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x23, 0x73, 0x69, 0x7a, 0x65,
+	0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x64, 0x65, 0x76, 0x69, 0x63,
+	0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67, 0x00, 0x6c,
+	0x69, 0x6e, 0x75, 0x78, 0x2c, 0x69, 0x6e, 0x69, 0x74, 0x72, 0x64, 0x2d,
+	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)
+{
+	struct boot_params params;
+	EXPECT_TRUE(
+		fdt_get_boot_params(pa_init((uintpaddr_t)&test_dtb), &params));
+	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));
+	EXPECT_THAT(pa_addr(params.mem_ranges[1].begin), Eq(0x30000000));
+	EXPECT_THAT(pa_addr(params.mem_ranges[1].end), Eq(0x30010000));
+	EXPECT_THAT(pa_addr(params.mem_ranges[2].begin), Eq(0x30020000));
+	EXPECT_THAT(pa_addr(params.mem_ranges[2].end), Eq(0x30030000));
+}
diff --git a/src/mock/BUILD.gn b/src/mock/BUILD.gn
new file mode 100644
index 0000000..594db5c
--- /dev/null
+++ b/src/mock/BUILD.gn
@@ -0,0 +1,5 @@
+source_set("mm") {
+  sources = [
+    "mm.c",
+  ]
+}
diff --git a/src/mock/mm.c b/src/mock/mm.c
new file mode 100644
index 0000000..3cc0f1f
--- /dev/null
+++ b/src/mock/mm.c
@@ -0,0 +1,68 @@
+#include "hf/mm.h"
+
+#include "hf/dlog.h"
+
+bool mm_init(void)
+{
+	return true;
+}
+
+bool mm_cpu_init(void)
+{
+	return true;
+}
+
+void mm_defrag(void)
+{
+}
+
+void *mm_identity_map(paddr_t begin, paddr_t end, int mode)
+{
+	(void)end;
+	(void)mode;
+	return ptr_from_va(va_from_pa(begin));
+}
+
+bool mm_unmap(paddr_t begin, paddr_t end, int mode)
+{
+	(void)begin;
+	(void)end;
+	(void)mode;
+	return false;
+}
+
+bool mm_vm_translate(struct mm_ptable *t, ipaddr_t ipa, paddr_t *pa)
+{
+	(void)t;
+	(void)ipa;
+	(void)pa;
+	return false;
+}
+
+bool mm_ptable_init(struct mm_ptable *t, int mode)
+{
+	(void)t;
+	(void)mode;
+	return true;
+}
+
+bool mm_vm_identity_map(struct mm_ptable *t, paddr_t begin, paddr_t end,
+			int mode, ipaddr_t *ipa)
+{
+	(void)t;
+	(void)end;
+	(void)mode;
+	*ipa = ipa_from_pa(begin);
+
+	return true;
+}
+
+bool mm_vm_identity_map_page(struct mm_ptable *t, paddr_t begin, int mode,
+			     ipaddr_t *ipa)
+{
+	(void)t;
+	(void)mode;
+	*ipa = ipa_from_pa(begin);
+
+	return true;
+}