1 /*
2  * Copyright 2019 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include <array>
10 #include <cstdio>
11 #include <span>
12 #include <sstream>
13 
14 #include <gmock/gmock.h>
15 
16 extern "C" {
17 #include "hf/arch/std.h"
18 
19 #include "hf/manifest.h"
20 #include "hf/sp_pkg.h"
21 }
22 
23 namespace
24 {
25 using ::testing::ElementsAre;
26 using ::testing::Eq;
27 using ::testing::IsEmpty;
28 using ::testing::NotNull;
29 
30 using struct_manifest = struct manifest;
31 
32 constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 32;
33 
34 template <typename T>
exec(const char * program,const char * args[],const T & stdin,std::vector<char> * stdout)35 void exec(const char *program, const char *args[], const T &stdin,
36 	  std::vector<char> *stdout)
37 {
38 	/* Create two pipes, one for stdin and one for stdout. */
39 	int pipes[2][2];
40 	pipe(pipes[0]);
41 	pipe(pipes[1]);
42 
43 	/* Assign FDs for reading/writing by the parent/child. */
44 	int parent_read_fd = pipes[1][0];  /* stdout pipe, read FD */
45 	int parent_write_fd = pipes[0][1]; /* stdin pipe, write FD */
46 	int child_read_fd = pipes[0][0];   /* stdin pipe, read FD */
47 	int child_write_fd = pipes[1][1];  /* stdout pipe, write FD */
48 
49 	if (fork()) {
50 		/* Parent process. */
51 		std::array<char, 128> buf;
52 		ssize_t res;
53 
54 		/* Close child FDs which won't be used. */
55 		close(child_read_fd);
56 		close(child_write_fd);
57 
58 		/* Write to stdin. */
59 		for (size_t count = 0; count < stdin.size();) {
60 			res = write(parent_write_fd, stdin.data() + count,
61 				    stdin.size() - count);
62 			if (res < 0) {
63 				std::cerr << "IO error" << std::endl;
64 				exit(1);
65 			}
66 			count += res;
67 		}
68 		close(parent_write_fd);
69 
70 		/* Read from stdout. */
71 		while (true) {
72 			res = read(parent_read_fd, buf.data(), buf.size());
73 			if (res == 0) {
74 				/* EOF */
75 				break;
76 			} else if (res < 0) {
77 				std::cerr << "IO error" << std::endl;
78 				exit(1);
79 			}
80 			stdout->insert(stdout->end(), buf.begin(),
81 				       buf.begin() + res);
82 		}
83 		close(parent_read_fd);
84 	} else {
85 		/* Child process. */
86 
87 		/* Redirect stdin/stdout to read/write FDs. */
88 		dup2(child_read_fd, STDIN_FILENO);
89 		dup2(child_write_fd, STDOUT_FILENO);
90 
91 		/* Close all FDs which are now unused. */
92 		close(child_read_fd);
93 		close(child_write_fd);
94 		close(parent_read_fd);
95 		close(parent_write_fd);
96 
97 		/* Execute the given program. */
98 		execv(program, const_cast<char *const *>(args));
99 	}
100 }
101 
102 /**
103  * Class for programatically building a Device Tree.
104  *
105  * Usage:
106  *   std::vector<char> dtb = ManifestDtBuilder()
107  *       .Command1()
108  *       .Command2()
109  *       ...
110  *       .CommandN()
111  *       .Build();
112  */
113 class ManifestDtBuilder
114 {
115        public:
ManifestDtBuilder()116 	ManifestDtBuilder()
117 	{
118 		dts_ << "/dts-v1/;" << std::endl;
119 		dts_ << std::endl;
120 
121 		/* Start root node. */
122 		StartChild("/");
123 	}
124 
Build(bool dump=false)125 	std::vector<char> Build(bool dump = false)
126 	{
127 		const char *program = "./build/image/dtc.py";
128 		const char *dtc_args[] = {program, "compile", NULL};
129 		std::vector<char> dtc_stdout;
130 
131 		/* Finish root node. */
132 		EndChild();
133 
134 		if (dump) {
135 			Dump();
136 		}
137 
138 		exec(program, dtc_args, dts_.str(), &dtc_stdout);
139 		return dtc_stdout;
140 	}
141 
Dump()142 	void Dump()
143 	{
144 		std::cerr << dts_.str() << std::endl;
145 	}
146 
StartChild(const std::string_view & name)147 	ManifestDtBuilder &StartChild(const std::string_view &name)
148 	{
149 		dts_ << name << " {" << std::endl;
150 		return *this;
151 	}
152 
EndChild()153 	ManifestDtBuilder &EndChild()
154 	{
155 		dts_ << "};" << std::endl;
156 		return *this;
157 	}
158 
Compatible(const std::vector<std::string_view> & value={"hafnium,hafnium"})159 	ManifestDtBuilder &Compatible(const std::vector<std::string_view>
160 					      &value = {"hafnium,hafnium"})
161 	{
162 		return StringListProperty("compatible", value);
163 	}
164 
DebugName(const std::string_view & value)165 	ManifestDtBuilder &DebugName(const std::string_view &value)
166 	{
167 		return StringProperty("debug_name", value);
168 	}
169 
Description(const std::string_view & value)170 	ManifestDtBuilder &Description(const std::string_view &value)
171 	{
172 		return StringProperty("description", value);
173 	}
174 
KernelFilename(const std::string_view & value)175 	ManifestDtBuilder &KernelFilename(const std::string_view &value)
176 	{
177 		return StringProperty("kernel_filename", value);
178 	}
179 
RamdiskFilename(const std::string_view & value)180 	ManifestDtBuilder &RamdiskFilename(const std::string_view &value)
181 	{
182 		return StringProperty("ramdisk_filename", value);
183 	}
184 
BootAddress(uint64_t value)185 	ManifestDtBuilder &BootAddress(uint64_t value)
186 	{
187 		return Integer64Property("boot_address", value);
188 	}
189 
VcpuCount(uint32_t value)190 	ManifestDtBuilder &VcpuCount(uint32_t value)
191 	{
192 		return IntegerProperty("vcpu_count", value);
193 	}
194 
MemSize(uint32_t value)195 	ManifestDtBuilder &MemSize(uint32_t value)
196 	{
197 		return IntegerProperty("mem_size", value);
198 	}
199 
SmcWhitelist(const std::vector<uint32_t> & value)200 	ManifestDtBuilder &SmcWhitelist(const std::vector<uint32_t> &value)
201 	{
202 		return IntegerListProperty("smc_whitelist", value);
203 	}
204 
SmcWhitelistPermissive()205 	ManifestDtBuilder &SmcWhitelistPermissive()
206 	{
207 		return BooleanProperty("smc_whitelist_permissive");
208 	}
209 
LoadAddress(uint64_t value)210 	ManifestDtBuilder &LoadAddress(uint64_t value)
211 	{
212 		return Integer64Property("load_address", value);
213 	}
214 
FfaPartition()215 	ManifestDtBuilder &FfaPartition()
216 	{
217 		return BooleanProperty("is_ffa_partition");
218 	}
219 
Property(const std::string_view & name,const std::string_view & value)220 	ManifestDtBuilder &Property(const std::string_view &name,
221 				    const std::string_view &value)
222 	{
223 		dts_ << name << " = " << value << ";" << std::endl;
224 		return *this;
225 	}
226 
Label(const std::string_view & name)227 	ManifestDtBuilder &Label(const std::string_view &name)
228 	{
229 		dts_ << name << ": ";
230 		return *this;
231 	}
232 
FfaValidManifest()233 	ManifestDtBuilder &FfaValidManifest()
234 	{
235 		Compatible({"arm,ffa-manifest-1.0"});
236 		Property("ffa-version", "<0x10000>");
237 		Property("uuid",
238 			 "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>");
239 		Property("execution-ctx-count", "<1>");
240 		Property("exception-level", "<2>");
241 		Property("execution-state", "<0>");
242 		Property("entrypoint-offset", "<0x00002000>");
243 		Property("xlat-granule", "<0>");
244 		Property("boot-order", "<0>");
245 		Property("messaging-method", "<4>");
246 		Property("ns-interrupts-action", "<1>");
247 		return *this;
248 	}
249 
250        private:
StringProperty(const std::string_view & name,const std::string_view & value)251 	ManifestDtBuilder &StringProperty(const std::string_view &name,
252 					  const std::string_view &value)
253 	{
254 		dts_ << name << " = \"" << value << "\";" << std::endl;
255 		return *this;
256 	}
257 
StringListProperty(const std::string_view & name,const std::vector<std::string_view> & value)258 	ManifestDtBuilder &StringListProperty(
259 		const std::string_view &name,
260 		const std::vector<std::string_view> &value)
261 	{
262 		bool is_first = true;
263 
264 		dts_ << name << " = ";
265 		for (const std::string_view &entry : value) {
266 			if (is_first) {
267 				is_first = false;
268 			} else {
269 				dts_ << ", ";
270 			}
271 			dts_ << "\"" << entry << "\"";
272 		}
273 		dts_ << ";" << std::endl;
274 		return *this;
275 	}
276 
IntegerProperty(const std::string_view & name,uint32_t value)277 	ManifestDtBuilder &IntegerProperty(const std::string_view &name,
278 					   uint32_t value)
279 	{
280 		dts_ << name << " = <" << value << ">;" << std::endl;
281 		return *this;
282 	}
283 
Integer64Property(const std::string_view & name,uint64_t value)284 	ManifestDtBuilder &Integer64Property(const std::string_view &name,
285 					     uint64_t value)
286 	{
287 		uint32_t high = value >> 32;
288 		uint32_t low = (uint32_t)value;
289 		dts_ << name << " = <" << high << " " << low << ">;"
290 		     << std::endl;
291 		return *this;
292 	}
293 
IntegerListProperty(const std::string_view & name,const std::vector<uint32_t> & value)294 	ManifestDtBuilder &IntegerListProperty(
295 		const std::string_view &name,
296 		const std::vector<uint32_t> &value)
297 	{
298 		dts_ << name << " = < ";
299 		for (const uint32_t entry : value) {
300 			dts_ << entry << " ";
301 		}
302 		dts_ << ">;" << std::endl;
303 		return *this;
304 	}
305 
BooleanProperty(const std::string_view & name)306 	ManifestDtBuilder &BooleanProperty(const std::string_view &name)
307 	{
308 		dts_ << name << ";" << std::endl;
309 		return *this;
310 	}
311 
312 	std::stringstream dts_;
313 };
314 
315 class manifest : public ::testing::Test
316 {
SetUp()317 	void SetUp() override
318 	{
319 		test_heap = std::make_unique<uint8_t[]>(TEST_HEAP_SIZE);
320 		mpool_init(&ppool, MM_PPOOL_ENTRY_SIZE);
321 		mpool_add_chunk(&ppool, test_heap.get(), TEST_HEAP_SIZE);
322 	}
323 
TearDown()324 	void TearDown() override
325 	{
326 		manifest_dealloc();
327 	}
328 
329 	std::unique_ptr<uint8_t[]> test_heap;
330 
331        protected:
332 	struct mpool ppool;
333 
manifest_dealloc(void)334 	void manifest_dealloc(void)
335 	{
336 		manifest_deinit(&ppool);
337 	}
338 
339        public:
340 	/**
341 	 * Class for programatically building a Partition package.
342 	 */
343 	class Partition_package
344 	{
345 	       public:
346 		__attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
347 		__attribute__((
348 			aligned(PAGE_SIZE))) char manifest_dtb[PAGE_SIZE] = {};
349 		__attribute__((aligned(PAGE_SIZE))) char img[PAGE_SIZE] = {};
350 
Partition_package(const std::vector<char> & vec)351 		Partition_package(const std::vector<char> &vec)
352 		{
353 			// Initialise header field
354 			spkg.magic = SP_PKG_HEADER_MAGIC;
355 			spkg.version = SP_PKG_HEADER_VERSION_2;
356 			spkg.pm_offset = PAGE_SIZE;
357 			spkg.pm_size = vec.size();
358 			spkg.img_offset = 2 * PAGE_SIZE;
359 			spkg.img_size = ARRAY_SIZE(img);
360 
361 			// Copy dtb into package
362 			std::copy(vec.begin(), vec.end(), manifest_dtb);
363 		}
364 	};
365 
manifest_from_vec(struct_manifest ** m,const std::vector<char> & vec)366 	enum manifest_return_code manifest_from_vec(
367 		struct_manifest **m, const std::vector<char> &vec)
368 	{
369 		struct memiter it;
370 		struct mm_stage1_locked mm_stage1_locked;
371 
372 		memiter_init(&it, vec.data(), vec.size());
373 
374 		return manifest_init(mm_stage1_locked, m, &it, &ppool);
375 	}
376 
ffa_manifest_from_vec(struct_manifest ** m,const std::vector<char> & vec)377 	enum manifest_return_code ffa_manifest_from_vec(
378 		struct_manifest **m, const std::vector<char> &vec)
379 	{
380 		struct memiter it;
381 		struct mm_stage1_locked mm_stage1_locked;
382 		Partition_package spkg(vec);
383 
384 		/* clang-format off */
385 		std::vector<char> core_dtb = ManifestDtBuilder()
386 			.StartChild("hypervisor")
387 				.Compatible()
388 				.StartChild("vm1")
389 					.DebugName("primary_vm")
390 					.FfaPartition()
391 					.LoadAddress((uint64_t)&spkg)
392 				.EndChild()
393 			.EndChild()
394 			.Build();
395 		/* clang-format on */
396 		memiter_init(&it, core_dtb.data(), core_dtb.size());
397 
398 		return manifest_init(mm_stage1_locked, m, &it, &ppool);
399 	}
400 };
401 
TEST_F(manifest,no_hypervisor_node)402 TEST_F(manifest, no_hypervisor_node)
403 {
404 	struct_manifest *m;
405 	std::vector<char> dtb = ManifestDtBuilder().Build();
406 
407 	ASSERT_EQ(manifest_from_vec(&m, dtb),
408 		  MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
409 }
410 
TEST_F(manifest,no_compatible_property)411 TEST_F(manifest, no_compatible_property)
412 {
413 	struct_manifest *m;
414 
415 	/* clang-format off */
416 	std::vector<char> dtb = ManifestDtBuilder()
417 		.StartChild("hypervisor")
418 		.EndChild()
419 		.Build();
420 	/* clang-format on */
421 
422 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
423 }
424 
TEST_F(manifest,not_compatible)425 TEST_F(manifest, not_compatible)
426 {
427 	struct_manifest *m;
428 
429 	/* clang-format off */
430 	std::vector<char> dtb = ManifestDtBuilder()
431 		.StartChild("hypervisor")
432 			.Compatible({ "foo,bar" })
433 		.EndChild()
434 		.Build();
435 	/* clang-format on */
436 
437 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
438 }
439 
TEST_F(manifest,compatible_one_of_many)440 TEST_F(manifest, compatible_one_of_many)
441 {
442 	struct_manifest *m;
443 
444 	/* clang-format off */
445 	std::vector<char> dtb = ManifestDtBuilder()
446 		.StartChild("hypervisor")
447 			.Compatible({ "foo,bar", "hafnium,hafnium" })
448 			.StartChild("vm1")
449 				.DebugName("primary")
450 			.EndChild()
451 		.EndChild()
452 		.Build();
453 	/* clang-format on */
454 
455 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
456 }
457 
TEST_F(manifest,no_vm_nodes)458 TEST_F(manifest, no_vm_nodes)
459 {
460 	struct_manifest *m;
461 
462 	/* clang-format off */
463 	std::vector<char> dtb = ManifestDtBuilder()
464 		.StartChild("hypervisor")
465 			.Compatible()
466 		.EndChild()
467 		.Build();
468 	/* clang-format on */
469 
470 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NO_PRIMARY_VM);
471 }
472 
gen_long_string_dtb(bool valid)473 static std::vector<char> gen_long_string_dtb(bool valid)
474 {
475 	const char last_valid[] = "1234567890123456789012345678901";
476 	const char first_invalid[] = "12345678901234567890123456789012";
477 	static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
478 	static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
479 
480 	/* clang-format off */
481 	return ManifestDtBuilder()
482 		.StartChild("hypervisor")
483 			.Compatible()
484 			.StartChild("vm1")
485 				.DebugName(valid ? last_valid : first_invalid)
486 			.EndChild()
487 		.EndChild()
488 		.Build();
489 	/* clang-format on */
490 }
491 
TEST_F(manifest,long_string)492 TEST_F(manifest, long_string)
493 {
494 	struct_manifest *m;
495 	std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
496 	std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
497 
498 	ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
499 	manifest_dealloc();
500 
501 	ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
502 		  MANIFEST_ERROR_STRING_TOO_LONG);
503 }
504 
TEST_F(manifest,reserved_vm_id)505 TEST_F(manifest, reserved_vm_id)
506 {
507 	struct_manifest *m;
508 
509 	/* clang-format off */
510 	std::vector<char> dtb = ManifestDtBuilder()
511 		.StartChild("hypervisor")
512 			.Compatible()
513 			.StartChild("vm1")
514 				.DebugName("primary_vm")
515 			.EndChild()
516 			.StartChild("vm0")
517 				.DebugName("reserved_vm")
518 				.VcpuCount(1)
519 				.MemSize(0x1000)
520 				.KernelFilename("kernel")
521 			.EndChild()
522 		.EndChild()
523 		.Build();
524 	/* clang-format on */
525 
526 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_RESERVED_VM_ID);
527 }
528 
gen_vcpu_count_limit_dtb(uint32_t vcpu_count)529 static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
530 {
531 	/* clang-format off */
532 	return ManifestDtBuilder()
533 		.StartChild("hypervisor")
534 			.Compatible()
535 			.StartChild("vm1")
536 				.DebugName("primary_vm")
537 			.EndChild()
538 			.StartChild("vm2")
539 				.DebugName("secondary_vm")
540 				.VcpuCount(vcpu_count)
541 				.MemSize(0x1000)
542 				.KernelFilename("kernel")
543 			.EndChild()
544 		.EndChild()
545 		.Build();
546 	/* clang-format on */
547 }
548 
TEST_F(manifest,vcpu_count_limit)549 TEST_F(manifest, vcpu_count_limit)
550 {
551 	struct_manifest *m;
552 	std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
553 	std::vector<char> dtb_first_invalid =
554 		gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
555 
556 	ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
557 	ASSERT_EQ(m->vm_count, 2);
558 	ASSERT_EQ(m->vm[1].secondary.vcpu_count, UINT16_MAX);
559 	manifest_dealloc();
560 
561 	ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
562 		  MANIFEST_ERROR_INTEGER_OVERFLOW);
563 }
564 
TEST_F(manifest,no_ramdisk_primary)565 TEST_F(manifest, no_ramdisk_primary)
566 {
567 	struct_manifest *m;
568 
569 	/* clang-format off */
570 	std::vector<char> dtb = ManifestDtBuilder()
571 		.StartChild("hypervisor")
572 			.Compatible()
573 			.StartChild("vm1")
574 				.DebugName("primary_vm")
575 			.EndChild()
576 		.EndChild()
577 		.Build();
578 	/* clang-format on */
579 
580 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
581 	ASSERT_EQ(m->vm_count, 1);
582 	ASSERT_STREQ(string_data(&m->vm[0].debug_name), "primary_vm");
583 	ASSERT_STREQ(string_data(&m->vm[0].primary.ramdisk_filename), "");
584 }
585 
TEST_F(manifest,no_boot_address_primary)586 TEST_F(manifest, no_boot_address_primary)
587 {
588 	struct_manifest *m;
589 
590 	/* clang-format off */
591 	std::vector<char> dtb = ManifestDtBuilder()
592 		.StartChild("hypervisor")
593 			.Compatible()
594 			.StartChild("vm1")
595 				.DebugName("primary_vm")
596 			.EndChild()
597 		.EndChild()
598 		.Build();
599 	/* clang-format on */
600 
601 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
602 	ASSERT_EQ(m->vm_count, 1);
603 	ASSERT_STREQ(string_data(&m->vm[0].debug_name), "primary_vm");
604 	ASSERT_EQ(m->vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
605 }
606 
TEST_F(manifest,boot_address_primary)607 TEST_F(manifest, boot_address_primary)
608 {
609 	struct_manifest *m;
610 	const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
611 
612 	/* clang-format off */
613 	std::vector<char> dtb = ManifestDtBuilder()
614 		.StartChild("hypervisor")
615 			.Compatible()
616 			.StartChild("vm1")
617 				.DebugName("primary_vm")
618 				.BootAddress(addr)
619 			.EndChild()
620 		.EndChild()
621 		.Build();
622 	/* clang-format on */
623 
624 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
625 	ASSERT_EQ(m->vm_count, 1);
626 	ASSERT_STREQ(string_data(&m->vm[0].debug_name), "primary_vm");
627 	ASSERT_EQ(m->vm[0].primary.boot_address, addr);
628 }
629 
gen_malformed_boolean_dtb(const std::string_view & value)630 static std::vector<char> gen_malformed_boolean_dtb(
631 	const std::string_view &value)
632 {
633 	/* clang-format off */
634 	return  ManifestDtBuilder()
635 		.StartChild("hypervisor")
636 			.Compatible()
637 			.StartChild("vm1")
638 				.DebugName("primary_vm")
639 				.Property("smc_whitelist_permissive", value)
640 			.EndChild()
641 		.EndChild()
642 		.Build();
643 	/* clang-format on */
644 }
645 
TEST_F(manifest,malformed_booleans)646 TEST_F(manifest, malformed_booleans)
647 {
648 	struct_manifest *m;
649 
650 	std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
651 	std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
652 	std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
653 	std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
654 
655 	ASSERT_EQ(manifest_from_vec(&m, dtb_false),
656 		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
657 	manifest_dealloc();
658 
659 	ASSERT_EQ(manifest_from_vec(&m, dtb_true),
660 		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
661 	manifest_dealloc();
662 
663 	ASSERT_EQ(manifest_from_vec(&m, dtb_0),
664 		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
665 	manifest_dealloc();
666 
667 	ASSERT_EQ(manifest_from_vec(&m, dtb_1),
668 		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
669 }
670 
TEST_F(manifest,valid)671 TEST_F(manifest, valid)
672 {
673 	struct_manifest *m;
674 	struct manifest_vm *vm;
675 
676 	/* clang-format off */
677 	std::vector<char> dtb = ManifestDtBuilder()
678 		.StartChild("hypervisor")
679 			.Compatible()
680 			.StartChild("vm1")
681 				.DebugName("primary_vm")
682 				.KernelFilename("primary_kernel")
683 				.RamdiskFilename("primary_ramdisk")
684 				.SmcWhitelist({0x32000000, 0x33001111})
685 			.EndChild()
686 			.StartChild("vm3")
687 				.DebugName("second_secondary_vm")
688 				.VcpuCount(43)
689 				.MemSize(0x12345)
690 				.KernelFilename("second_secondary_kernel")
691 			.EndChild()
692 			.StartChild("vm2")
693 				.DebugName("first_secondary_vm")
694 				.VcpuCount(42)
695 				.MemSize(12345)
696 				.SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
697 				.SmcWhitelistPermissive()
698 			.EndChild()
699 		.EndChild()
700 		.Build();
701 	/* clang-format on */
702 
703 	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
704 	ASSERT_EQ(m->vm_count, 3);
705 
706 	vm = &m->vm[0];
707 	ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
708 	ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
709 	ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
710 		     "primary_ramdisk");
711 	ASSERT_THAT(
712 		std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
713 		ElementsAre(0x32000000, 0x33001111));
714 	ASSERT_FALSE(vm->smc_whitelist.permissive);
715 
716 	vm = &m->vm[1];
717 	ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
718 	ASSERT_STREQ(string_data(&vm->kernel_filename), "");
719 	ASSERT_EQ(vm->secondary.vcpu_count, 42);
720 	ASSERT_EQ(vm->secondary.mem_size, 12345);
721 	ASSERT_THAT(
722 		std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
723 		ElementsAre(0x04000000, 0x30002222, 0x31445566));
724 	ASSERT_TRUE(vm->smc_whitelist.permissive);
725 
726 	vm = &m->vm[2];
727 	ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
728 	ASSERT_STREQ(string_data(&vm->kernel_filename),
729 		     "second_secondary_kernel");
730 	ASSERT_EQ(vm->secondary.vcpu_count, 43);
731 	ASSERT_EQ(vm->secondary.mem_size, 0x12345);
732 	ASSERT_THAT(
733 		std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
734 		IsEmpty());
735 	ASSERT_FALSE(vm->smc_whitelist.permissive);
736 }
737 
TEST_F(manifest,ffa_not_compatible)738 TEST_F(manifest, ffa_not_compatible)
739 {
740 	struct_manifest *m;
741 
742 	/* clang-format off */
743 	std::vector<char>  dtb = ManifestDtBuilder()
744 		.Compatible({ "arm,ffa-manifest-2.0" })
745 		.Property("ffa-version", "<0x10000>")
746 		.Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
747 		.Property("execution-ctx-count", "<1>")
748 		.Property("exception-level", "<2>")
749 		.Property("execution-state", "<0>")
750 		.Property("entrypoint-offset", "<0x00002000>")
751 		.Property("xlat-granule", "<0>")
752 		.Property("messaging-method", "<1>")
753 		.Property("ns-interrupts-action", "<1>")
754 		.Build();
755 	/* clang-format on */
756 
757 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
758 		  MANIFEST_ERROR_NOT_COMPATIBLE);
759 }
760 
TEST_F(manifest,ffa_missing_property)761 TEST_F(manifest, ffa_missing_property)
762 {
763 	struct_manifest *m;
764 
765 	/* clang-format off */
766 	std::vector<char>  dtb = ManifestDtBuilder()
767 		.Compatible({ "arm,ffa-manifest-1.0" })
768 		.Property("ffa-version", "<0x10000>")
769 		.Build();
770 	/* clang-format on */
771 
772 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
773 		  MANIFEST_ERROR_PROPERTY_NOT_FOUND);
774 }
775 
TEST_F(manifest,ffa_validate_sanity_check)776 TEST_F(manifest, ffa_validate_sanity_check)
777 {
778 	/*
779 	 * TODO: write test excluding all optional fields of the manifest, in
780 	 * accordance with specification.
781 	 */
782 	struct_manifest *m;
783 
784 	/* Incompatible version */
785 	/* clang-format off */
786 	std::vector<char>  dtb = ManifestDtBuilder()
787 		.Compatible({ "arm,ffa-manifest-1.0" })
788 		.Property("ffa-version", "<0xa1>")
789 		.Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
790 		.Property("execution-ctx-count", "<1>")
791 		.Property("exception-level", "<2>")
792 		.Property("execution-state", "<0>")
793 		.Property("entrypoint-offset", "<0x00002000>")
794 		.Property("xlat-granule", "<0>")
795 		.Property("boot-order", "<0>")
796 		.Property("messaging-method", "<1>")
797 		.Property("ns-interrupts-action", "<1>")
798 		.Build();
799 	/* clang-format on */
800 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
801 		  MANIFEST_ERROR_NOT_COMPATIBLE);
802 	manifest_dealloc();
803 
804 	/* Incompatible translation granule */
805 	/* clang-format off */
806 	dtb = ManifestDtBuilder()
807 		.Compatible({ "arm,ffa-manifest-1.0" })
808 		.Property("ffa-version", "<0x10000>")
809 		.Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
810 		.Property("execution-ctx-count", "<1>")
811 		.Property("exception-level", "<2>")
812 		.Property("execution-state", "<0>")
813 		.Property("entrypoint-offset", "<0x00002000>")
814 		.Property("xlat-granule", "<3>")
815 		.Property("boot-order", "<0>")
816 		.Property("messaging-method", "<1>")
817 		.Property("ns-interrupts-action", "<1>")
818 		.Build();
819 	/* clang-format on */
820 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
821 		  MANIFEST_ERROR_NOT_COMPATIBLE);
822 	manifest_dealloc();
823 
824 	/* Incompatible exeption level */
825 	/* clang-format off */
826 	dtb = ManifestDtBuilder()
827 		.Compatible({ "arm,ffa-manifest-1.0" })
828 		.Property("ffa-version", "<0x10000>")
829 		.Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
830 		.Property("execution-ctx-count", "<1>")
831 		.Property("exception-level", "<6>")
832 		.Property("execution-state", "<0>")
833 		.Property("entrypoint-offset", "<0x00002000>")
834 		.Property("xlat-granule", "<0>")
835 		.Property("boot-order", "<0>")
836 		.Property("messaging-method", "<1>")
837 		.Property("ns-interrupts-action", "<0>")
838 		.Build();
839 	/* clang-format on */
840 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
841 		  MANIFEST_ERROR_NOT_COMPATIBLE);
842 	manifest_dealloc();
843 
844 	/* Incompatible execution state */
845 	/* clang-format off */
846 	dtb = ManifestDtBuilder()
847 		.Compatible({ "arm,ffa-manifest-1.0" })
848 		.Property("ffa-version", "<0x10000>")
849 		.Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
850 		.Property("execution-ctx-count", "<1>")
851 		.Property("exception-level", "<2>")
852 		.Property("execution-state", "<2>")
853 		.Property("entrypoint-offset", "<0x00002000>")
854 		.Property("xlat-granule", "<0>")
855 		.Property("boot-order", "<0>")
856 		.Property("messaging-method", "<1>")
857 		.Property("ns-interrupts-action", "<0>")
858 		.Build();
859 	/* clang-format on */
860 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
861 		  MANIFEST_ERROR_NOT_COMPATIBLE);
862 	manifest_dealloc();
863 
864 	/* Incompatible messaging method */
865 	/* clang-format off */
866 	dtb = ManifestDtBuilder()
867 		.Compatible({ "arm,ffa-manifest-1.0" })
868 		.Property("ffa-version", "<0x10000>")
869 		.Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
870 		.Property("execution-ctx-count", "<1>")
871 		.Property("exception-level", "<2>")
872 		.Property("execution-state", "<0>")
873 		.Property("entrypoint-offset", "<0x00002000>")
874 		.Property("xlat-granule", "<0>")
875 		.Property("boot-order", "<0>")
876 		.Property("messaging-method", "<16>")
877 		.Property("ns-interrupts-action", "<0>")
878 		.Build();
879 	/* clang-format on */
880 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
881 		  MANIFEST_ERROR_NOT_COMPATIBLE);
882 	manifest_dealloc();
883 
884 	/* Incompatible NS interrupt action */
885 	/* clang-format off */
886 	dtb = ManifestDtBuilder()
887 		.Compatible({ "arm,ffa-manifest-1.0" })
888 		.Property("ffa-version", "<0x10000>")
889 		.Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
890 		.Property("execution-ctx-count", "<1>")
891 		.Property("exception-level", "<2>")
892 		.Property("execution-state", "<0>")
893 		.Property("entrypoint-offset", "<0x00002000>")
894 		.Property("xlat-granule", "<0>")
895 		.Property("boot-order", "<0>")
896 		.Property("messaging-method", "<1>")
897 		.Property("ns-interrupts-action", "<4>")
898 		.Build();
899 	/* clang-format on */
900 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_ILLEGAL_NS_ACTION);
901 }
902 
TEST_F(manifest,ffa_validate_rxtx_info)903 TEST_F(manifest, ffa_validate_rxtx_info)
904 {
905 	struct_manifest *m;
906 
907 	/* Not Compatible */
908 	/* clang-format off */
909 	std::vector<char>  dtb = ManifestDtBuilder()
910 		.FfaValidManifest()
911 		.StartChild("rx_tx-info")
912 			.Compatible({ "foo,bar" })
913 		.EndChild()
914 		.Build();
915 	/* clang-format on */
916 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
917 		  MANIFEST_ERROR_NOT_COMPATIBLE);
918 	manifest_dealloc();
919 
920 	/* Missing Properties */
921 	/* clang-format off */
922 	dtb = ManifestDtBuilder()
923 		.FfaValidManifest()
924 		.StartChild("rx_tx-info")
925 			.Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
926 		.EndChild()
927 		.Build();
928 	/* clang-format on */
929 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
930 		  MANIFEST_ERROR_PROPERTY_NOT_FOUND);
931 }
932 
TEST_F(manifest,ffa_validate_mem_regions)933 TEST_F(manifest, ffa_validate_mem_regions)
934 {
935 	struct_manifest *m;
936 
937 	/* Not Compatible */
938 	/* clang-format off */
939 	std::vector<char>  dtb = ManifestDtBuilder()
940 		.FfaValidManifest()
941 		.StartChild("memory-regions")
942 			.Compatible({ "foo,bar" })
943 		.EndChild()
944 		.Build();
945 	/* clang-format on */
946 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
947 		  MANIFEST_ERROR_NOT_COMPATIBLE);
948 	manifest_dealloc();
949 
950 	/* Memory regions unavailable  */
951 	/* clang-format off */
952 	dtb = ManifestDtBuilder()
953 		.FfaValidManifest()
954 		.StartChild("memory-regions")
955 			.Compatible({ "arm,ffa-manifest-memory-regions" })
956 		.EndChild()
957 		.Build();
958 	/* clang-format on */
959 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
960 		  MANIFEST_ERROR_MEMORY_REGION_NODE_EMPTY);
961 	manifest_dealloc();
962 
963 	/* Missing Properties */
964 	/* clang-format off */
965 	dtb = ManifestDtBuilder()
966 		.FfaValidManifest()
967 		.StartChild("memory-regions")
968 			.Compatible({ "arm,ffa-manifest-memory-regions" })
969 			.StartChild("test-memory")
970 				.Description("test-memory")
971 			.EndChild()
972 		.EndChild()
973 		.Build();
974 	/* clang-format on */
975 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
976 		  MANIFEST_ERROR_PROPERTY_NOT_FOUND);
977 	manifest_dealloc();
978 
979 	/* Overlapping memory regions */
980 	/* clang-format off */
981 	dtb = ManifestDtBuilder()
982 		.FfaValidManifest()
983 		.StartChild("memory-regions")
984 			.Compatible({ "arm,ffa-manifest-memory-regions" })
985 			.Label("rx")
986 			.StartChild("rx")
987 				.Description("rx-buffer")
988 				.Property("base-address", "<0x7300000>")
989 				.Property("pages-count", "<1>")
990 				.Property("attributes", "<1>")
991 			.EndChild()
992 			.Label("tx")
993 			.StartChild("tx")
994 				.Description("tx-buffer")
995 				.Property("base-address", "<0x7300000>")
996 				.Property("pages-count", "<2>")
997 				.Property("attributes", "<3>")
998 			.EndChild()
999 		.EndChild()
1000 		.Build();
1001 	/* clang-format on */
1002 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1003 		  MANIFEST_ERROR_MEM_REGION_OVERLAP);
1004 	manifest_dealloc();
1005 
1006 	/* clang-format off */
1007 	dtb = ManifestDtBuilder()
1008 		.FfaValidManifest()
1009 		.StartChild("memory-regions")
1010 			.Compatible({ "arm,ffa-manifest-memory-regions" })
1011 			.Label("rx")
1012 			.StartChild("rx")
1013 				.Description("rx-buffer")
1014 				.Property("base-address", "<0x7300000>")
1015 				.Property("pages-count", "<2>")
1016 				.Property("attributes", "<1>")
1017 			.EndChild()
1018 			.Label("tx")
1019 			.StartChild("tx")
1020 				.Description("tx-buffer")
1021 				.Property("base-address", "<0x7301000>")
1022 				.Property("pages-count", "<2>")
1023 				.Property("attributes", "<3>")
1024 			.EndChild()
1025 		.EndChild()
1026 		.Build();
1027 	/* clang-format on */
1028 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1029 		  MANIFEST_ERROR_MEM_REGION_OVERLAP);
1030 	manifest_dealloc();
1031 
1032 	/* clang-format off */
1033 	dtb = ManifestDtBuilder()
1034 		.FfaValidManifest()
1035 		.StartChild("memory-regions")
1036 			.Compatible({ "arm,ffa-manifest-memory-regions" })
1037 			.Label("rx")
1038 			.StartChild("rx")
1039 				.Description("rx-buffer")
1040 				.Property("base-address", "<0x7300000>")
1041 				.Property("pages-count", "<2>")
1042 				.Property("attributes", "<1>")
1043 			.EndChild()
1044 			.Label("tx")
1045 			.StartChild("tx")
1046 				.Description("tx-buffer")
1047 				.Property("base-address", "<0x7301FFF>")
1048 				.Property("pages-count", "<2>")
1049 				.Property("attributes", "<3>")
1050 			.EndChild()
1051 		.EndChild()
1052 		.Build();
1053 	/* clang-format on */
1054 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1055 		  MANIFEST_ERROR_MEM_REGION_OVERLAP);
1056 	manifest_dealloc();
1057 
1058 	/* Different RXTX buffer sizes */
1059 	/* clang-format off */
1060 	dtb = ManifestDtBuilder()
1061 		.FfaValidManifest()
1062 		.StartChild("memory-regions")
1063 			.Compatible({ "arm,ffa-manifest-memory-regions" })
1064 			.Label("rx")
1065 			.StartChild("rx")
1066 				.Description("rx-buffer")
1067 				.Property("base-address", "<0x7300000>")
1068 				.Property("pages-count", "<1>")
1069 				.Property("attributes", "<1>")
1070 			.EndChild()
1071 			.Label("tx")
1072 			.StartChild("tx")
1073 				.Description("tx-buffer")
1074 				.Property("base-address", "<0x7310000>")
1075 				.Property("pages-count", "<2>")
1076 				.Property("attributes", "<3>")
1077 			.EndChild()
1078 		.EndChild()
1079 		.StartChild("rx_tx-info")
1080 			.Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1081 			.Property("rx-buffer", "<&rx>")
1082 			.Property("tx-buffer", "<&tx>")
1083 		.EndChild()
1084 		.Build();
1085 	/* clang-format on */
1086 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1087 		  MANIFEST_ERROR_RXTX_SIZE_MISMATCH);
1088 }
1089 
TEST_F(manifest,ffa_validate_dev_regions)1090 TEST_F(manifest, ffa_validate_dev_regions)
1091 {
1092 	struct_manifest *m;
1093 
1094 	/* Not Compatible */
1095 	/* clang-format off */
1096 	std::vector<char>  dtb = ManifestDtBuilder()
1097 		.FfaValidManifest()
1098 		.StartChild("device-regions")
1099 			.Compatible({ "foo,bar" })
1100 		.EndChild()
1101 		.Build();
1102 	/* clang-format on */
1103 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1104 		  MANIFEST_ERROR_NOT_COMPATIBLE);
1105 	manifest_dealloc();
1106 
1107 	/* Memory regions unavailable  */
1108 	/* clang-format off */
1109 	dtb = ManifestDtBuilder()
1110 		.FfaValidManifest()
1111 		.StartChild("device-regions")
1112 			.Compatible({ "arm,ffa-manifest-device-regions" })
1113 		.EndChild()
1114 		.Build();
1115 	/* clang-format on */
1116 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1117 		  MANIFEST_ERROR_DEVICE_REGION_NODE_EMPTY);
1118 	manifest_dealloc();
1119 
1120 	/* Missing Properties */
1121 	/* clang-format off */
1122 	dtb = ManifestDtBuilder()
1123 		.FfaValidManifest()
1124 		.StartChild("device-regions")
1125 			.Compatible({ "arm,ffa-manifest-device-regions" })
1126 			.StartChild("test-device")
1127 				.Description("test-device")
1128 			.EndChild()
1129 		.EndChild()
1130 		.Build();
1131 	/* clang-format on */
1132 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1133 		  MANIFEST_ERROR_PROPERTY_NOT_FOUND);
1134 	manifest_dealloc();
1135 
1136 	/* Malformed interrupt list pair */
1137 	/* clang-format off */
1138 	dtb = ManifestDtBuilder()
1139 		.FfaValidManifest()
1140 		.StartChild("device-regions")
1141 			.Compatible({ "arm,ffa-manifest-device-regions" })
1142 			.StartChild("test-device")
1143 				.Description("test-device")
1144 				.Property("base-address", "<0x7200000>")
1145 				.Property("pages-count", "<16>")
1146 				.Property("attributes", "<3>")
1147 				.Property("smmu-id", "<1>")
1148 				.Property("stream-ids", "<0 1>")
1149 				.Property("interrupts", "<2 3>, <4>")
1150 			.EndChild()
1151 		.EndChild()
1152 		.Build();
1153 	/* clang-format on */
1154 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1155 		  MANIFEST_ERROR_MALFORMED_INTEGER_LIST);
1156 	manifest_dealloc();
1157 
1158 	/* Non-unique interrupt IDs */
1159 	/* clang-format off */
1160 	dtb = ManifestDtBuilder()
1161 		.FfaValidManifest()
1162 		.StartChild("device-regions")
1163 			.Compatible({ "arm,ffa-manifest-device-regions" })
1164 			.StartChild("test-device-0")
1165 				.Description("test-device-0")
1166 				.Property("base-address", "<0x7200000>")
1167 				.Property("pages-count", "<16>")
1168 				.Property("attributes", "<3>")
1169 				.Property("interrupts", "<2 3>")
1170 			.EndChild()
1171 			.StartChild("test-device-1")
1172 				.Description("test-device-1")
1173 				.Property("base-address", "<0x8200000>")
1174 				.Property("pages-count", "<16>")
1175 				.Property("attributes", "<3>")
1176 				.Property("interrupts", "<1 3>, <2 5> ")
1177 			.EndChild()
1178 		.EndChild()
1179 		.Build();
1180 	/* clang-format on */
1181 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1182 		  MANIFEST_ERROR_INTERRUPT_ID_REPEATED);
1183 	/* Check valid interrupts were still mapped */
1184 	ASSERT_EQ(m->vm[0].partition.dev_regions[0].interrupts[0].id, 2);
1185 	ASSERT_EQ(m->vm[0].partition.dev_regions[0].interrupts[0].attributes,
1186 		  3);
1187 	ASSERT_EQ(m->vm[0].partition.dev_regions[1].interrupts[0].id, 1);
1188 	ASSERT_EQ(m->vm[0].partition.dev_regions[1].interrupts[0].attributes,
1189 		  3);
1190 }
1191 
TEST_F(manifest,ffa_invalid_memory_region_attributes)1192 TEST_F(manifest, ffa_invalid_memory_region_attributes)
1193 {
1194 	struct_manifest *m;
1195 
1196 	/* clang-format off */
1197 	std::vector<char>  dtb = ManifestDtBuilder()
1198 		.FfaValidManifest()
1199 		.StartChild("rx_tx-info")
1200 			.Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1201 			.Property("rx-buffer", "<&rx>")
1202 			.Property("tx-buffer", "<&tx>")
1203 		.EndChild()
1204 		.StartChild("memory-regions")
1205 			.Compatible({ "arm,ffa-manifest-memory-regions" })
1206 			.StartChild("test-memory")
1207 				.Description("test-memory")
1208 				.Property("base-address", "<0x7100000>")
1209 				.Property("pages-count", "<4>")
1210 				.Property("attributes", "<7>")
1211 			.EndChild()
1212 			.Label("rx")
1213 			.StartChild("rx")
1214 				.Description("rx-buffer")
1215 				.Property("base-address", "<0x7300000>")
1216 				.Property("pages-count", "<1>")
1217 				.Property("attributes", "<1>")
1218 			.EndChild()
1219 			.Label("tx")
1220 			.StartChild("tx")
1221 				.Description("tx-buffer")
1222 				.Property("base-address", "<0x7310000>")
1223 				.Property("pages-count", "<1>")
1224 				.Property("attributes", "<3>")
1225 			.EndChild()
1226 		.EndChild()
1227 		.Build();
1228 	/* clang-format on */
1229 
1230 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1231 		  MANIFEST_ERROR_INVALID_MEM_PERM);
1232 }
1233 
TEST_F(manifest,ffa_invalid_device_region_attributes)1234 TEST_F(manifest, ffa_invalid_device_region_attributes)
1235 {
1236 	struct_manifest *m;
1237 
1238 	/* clang-format off */
1239 	std::vector<char>  dtb = ManifestDtBuilder()
1240 		.FfaValidManifest()
1241 		.StartChild("rx_tx-info")
1242 			.Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1243 			.Property("rx-buffer", "<&rx>")
1244 			.Property("tx-buffer", "<&tx>")
1245 		.EndChild()
1246 		.StartChild("memory-regions")
1247 			.Compatible({ "arm,ffa-manifest-memory-regions" })
1248 			.StartChild("test-memory")
1249 				.Description("test-memory")
1250 				.Property("base-address", "<0x7100000>")
1251 				.Property("pages-count", "<4>")
1252 				.Property("attributes", "<3>")
1253 			.EndChild()
1254 			.Label("rx")
1255 			.StartChild("rx")
1256 				.Description("rx-buffer")
1257 				.Property("base-address", "<0x7300000>")
1258 				.Property("pages-count", "<1>")
1259 				.Property("attributes", "<1>")
1260 			.EndChild()
1261 			.Label("tx")
1262 			.StartChild("tx")
1263 				.Description("tx-buffer")
1264 				.Property("base-address", "<0x7310000>")
1265 				.Property("pages-count", "<1>")
1266 				.Property("attributes", "<3>")
1267 			.EndChild()
1268 		.EndChild()
1269 		.StartChild("device-regions")
1270 			.Compatible({ "arm,ffa-manifest-device-regions" })
1271 			.StartChild("test-device")
1272 				.Description("test-device")
1273 				.Property("base-address", "<0x7200000>")
1274 				.Property("pages-count", "<16>")
1275 				.Property("attributes", "<5>")
1276 				.Property("smmu-id", "<1>")
1277 				.Property("stream-ids", "<0 1>")
1278 				.Property("interrupts", "<2 3>, <4 5>")
1279 			.EndChild()
1280 		.EndChild()
1281 		.Build();
1282 	/* clang-format on */
1283 
1284 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1285 		  MANIFEST_ERROR_INVALID_MEM_PERM);
1286 }
1287 
TEST_F(manifest,ffa_valid)1288 TEST_F(manifest, ffa_valid)
1289 {
1290 	struct manifest_vm *vm;
1291 	struct_manifest *m;
1292 
1293 	/* clang-format off */
1294 	std::vector<char>  dtb = ManifestDtBuilder()
1295 		.FfaValidManifest()
1296 		.StartChild("rx_tx-info")
1297 			.Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1298 			.Property("rx-buffer", "<&rx>")
1299 			.Property("tx-buffer", "<&tx>")
1300 		.EndChild()
1301 		.StartChild("memory-regions")
1302 			.Compatible({ "arm,ffa-manifest-memory-regions" })
1303 			.StartChild("test-memory")
1304 				.Description("test-memory")
1305 				.Property("base-address", "<0x7100000>")
1306 				.Property("pages-count", "<4>")
1307 				.Property("attributes", "<3>")
1308 			.EndChild()
1309 			.StartChild("test-memory-ns")
1310 				.Description("test-memory")
1311 				.Property("base-address", "<0x7200000>")
1312 				.Property("pages-count", "<1>")
1313 				.Property("attributes", "<0xb>")
1314 			.EndChild()
1315 			.Label("rx")
1316 			.StartChild("rx")
1317 				.Description("rx-buffer")
1318 				.Property("base-address", "<0x7300000>")
1319 				.Property("pages-count", "<1>")
1320 				.Property("attributes", "<1>")
1321 			.EndChild()
1322 			.Label("tx")
1323 			.StartChild("tx")
1324 				.Description("tx-buffer")
1325 				.Property("base-address", "<0x7301000>")
1326 				.Property("pages-count", "<1>")
1327 				.Property("attributes", "<3>")
1328 			.EndChild()
1329 		.EndChild()
1330 		.StartChild("device-regions")
1331 			.Compatible({ "arm,ffa-manifest-device-regions" })
1332 			.StartChild("test-device")
1333 				.Description("test-device")
1334 				.Property("base-address", "<0x7400000>")
1335 				.Property("pages-count", "<16>")
1336 				.Property("attributes", "<3>")
1337 				.Property("smmu-id", "<1>")
1338 				.Property("stream-ids", "<0 1>")
1339 				.Property("interrupts", "<2 3>, <4 5>")
1340 			.EndChild()
1341 			.StartChild("test-device-ns")
1342 				.Description("test-device")
1343 				.Property("base-address", "<0x7500000>")
1344 				.Property("pages-count", "<1>")
1345 				.Property("attributes", "<0x9>")
1346 			.EndChild()
1347 		.EndChild()
1348 		.Build();
1349 	/* clang-format on */
1350 
1351 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
1352 
1353 	vm = &m->vm[0];
1354 	ASSERT_EQ(vm->partition.ffa_version, 0x10000);
1355 	ASSERT_THAT(
1356 		std::span(vm->partition.uuid.uuid, 4),
1357 		ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb));
1358 	ASSERT_EQ(vm->partition.execution_ctx_count, 1);
1359 	ASSERT_EQ(vm->partition.run_time_el, S_EL1);
1360 	ASSERT_EQ(vm->partition.execution_state, AARCH64);
1361 	ASSERT_EQ(vm->partition.ep_offset, 0x00002000);
1362 	ASSERT_EQ(vm->partition.xlat_granule, PAGE_4KB);
1363 	ASSERT_EQ(vm->partition.boot_order, 0);
1364 	ASSERT_EQ(vm->partition.messaging_method, FFA_PARTITION_INDIRECT_MSG);
1365 	ASSERT_EQ(vm->partition.ns_interrupts_action, NS_ACTION_ME);
1366 	ASSERT_EQ(vm->partition.mem_regions[0].base_address, 0x7100000);
1367 	ASSERT_EQ(vm->partition.mem_regions[0].page_count, 4);
1368 	ASSERT_EQ(vm->partition.mem_regions[0].attributes, 3);
1369 	ASSERT_EQ(vm->partition.mem_regions[1].attributes, (8 | 3));
1370 
1371 	ASSERT_EQ(vm->partition.rxtx.available, true);
1372 	ASSERT_EQ(vm->partition.rxtx.rx_buffer->base_address, 0x7300000);
1373 	ASSERT_EQ(vm->partition.rxtx.rx_buffer->page_count, 1);
1374 	ASSERT_EQ(vm->partition.rxtx.rx_buffer->attributes, 1);
1375 	ASSERT_EQ(vm->partition.rxtx.tx_buffer->base_address, 0x7301000);
1376 	ASSERT_EQ(vm->partition.rxtx.tx_buffer->page_count, 1);
1377 	ASSERT_EQ(vm->partition.rxtx.tx_buffer->attributes, 3);
1378 
1379 	ASSERT_EQ(vm->partition.dev_regions[0].base_address, 0x7400000);
1380 	ASSERT_EQ(vm->partition.dev_regions[0].page_count, 16);
1381 	ASSERT_EQ(vm->partition.dev_regions[0].attributes, 3);
1382 	ASSERT_EQ(vm->partition.dev_regions[0].smmu_id, 1);
1383 	ASSERT_EQ(vm->partition.dev_regions[0].stream_ids[0], 0);
1384 	ASSERT_EQ(vm->partition.dev_regions[0].stream_ids[1], 1);
1385 	ASSERT_EQ(vm->partition.dev_regions[0].interrupts[0].id, 2);
1386 	ASSERT_EQ(vm->partition.dev_regions[0].interrupts[0].attributes, 3);
1387 	ASSERT_EQ(vm->partition.dev_regions[0].interrupts[1].id, 4);
1388 	ASSERT_EQ(vm->partition.dev_regions[0].interrupts[1].attributes, 5);
1389 	ASSERT_EQ(vm->partition.dev_regions[1].attributes, (8 | 1));
1390 }
1391 
1392 } /* namespace */
1393