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