blob: 0a71f8bbb467eff677538bb93934e49346f113b7 [file] [log] [blame]
David Brazdil7a462ec2019-08-15 12:27:47 +01001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * 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.
David Brazdil7a462ec2019-08-15 12:27:47 +01007 */
8
David Brazdil52256ff2019-08-23 15:15:15 +01009#include <array>
10#include <cstdio>
Andrew Scullae9962e2019-10-03 16:51:16 +010011#include <span>
David Brazdil52256ff2019-08-23 15:15:15 +010012#include <sstream>
13
David Brazdil7a462ec2019-08-15 12:27:47 +010014#include <gmock/gmock.h>
15
16extern "C" {
J-Alves2f86c1e2022-02-23 18:44:19 +000017#include "hf/arch/std.h"
18
David Brazdil7a462ec2019-08-15 12:27:47 +010019#include "hf/manifest.h"
J-Alves2f86c1e2022-02-23 18:44:19 +000020#include "hf/sp_pkg.h"
David Brazdil7a462ec2019-08-15 12:27:47 +010021}
22
23namespace
24{
Andrew Scullae9962e2019-10-03 16:51:16 +010025using ::testing::ElementsAre;
David Brazdil7a462ec2019-08-15 12:27:47 +010026using ::testing::Eq;
Andrew Scullae9962e2019-10-03 16:51:16 +010027using ::testing::IsEmpty;
David Brazdil7a462ec2019-08-15 12:27:47 +010028using ::testing::NotNull;
29
Daniel Boulby801f8ef2022-06-27 14:21:01 +010030using struct_manifest = struct manifest;
31
32constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 32;
33
David Brazdil52256ff2019-08-23 15:15:15 +010034template <typename T>
David Brazdil0dbb41f2019-09-09 18:03:35 +010035void exec(const char *program, const char *args[], const T &stdin,
David Brazdil52256ff2019-08-23 15:15:15 +010036 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]);
David Brazdil7a462ec2019-08-15 12:27:47 +010042
David Brazdil52256ff2019-08-23 15:15:15 +010043 /* 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 */
David Brazdil7a462ec2019-08-15 12:27:47 +010048
David Brazdil52256ff2019-08-23 15:15:15 +010049 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. */
David Brazdil0dbb41f2019-09-09 18:03:35 +010098 execv(program, const_cast<char *const *>(args));
David Brazdil52256ff2019-08-23 15:15:15 +010099 }
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 */
113class ManifestDtBuilder
114{
115 public:
116 ManifestDtBuilder()
117 {
118 dts_ << "/dts-v1/;" << std::endl;
119 dts_ << std::endl;
120
121 /* Start root node. */
122 StartChild("/");
123 }
124
Andrew Scullae9962e2019-10-03 16:51:16 +0100125 std::vector<char> Build(bool dump = false)
David Brazdil52256ff2019-08-23 15:15:15 +0100126 {
David Brazdil0dbb41f2019-09-09 18:03:35 +0100127 const char *program = "./build/image/dtc.py";
128 const char *dtc_args[] = {program, "compile", NULL};
David Brazdil52256ff2019-08-23 15:15:15 +0100129 std::vector<char> dtc_stdout;
130
131 /* Finish root node. */
132 EndChild();
133
Andrew Scullae9962e2019-10-03 16:51:16 +0100134 if (dump) {
135 Dump();
136 }
137
David Brazdil0dbb41f2019-09-09 18:03:35 +0100138 exec(program, dtc_args, dts_.str(), &dtc_stdout);
David Brazdil52256ff2019-08-23 15:15:15 +0100139 return dtc_stdout;
140 }
141
Andrew Scullae9962e2019-10-03 16:51:16 +0100142 void Dump()
143 {
144 std::cerr << dts_.str() << std::endl;
145 }
146
David Brazdil52256ff2019-08-23 15:15:15 +0100147 ManifestDtBuilder &StartChild(const std::string_view &name)
148 {
149 dts_ << name << " {" << std::endl;
150 return *this;
151 }
152
153 ManifestDtBuilder &EndChild()
154 {
155 dts_ << "};" << std::endl;
156 return *this;
157 }
158
David Brazdil74e9c3b2019-08-28 11:09:08 +0100159 ManifestDtBuilder &Compatible(const std::vector<std::string_view>
160 &value = {"hafnium,hafnium"})
161 {
162 return StringListProperty("compatible", value);
163 }
164
David Brazdil52256ff2019-08-23 15:15:15 +0100165 ManifestDtBuilder &DebugName(const std::string_view &value)
166 {
167 return StringProperty("debug_name", value);
168 }
169
Manish Pandey6542f5c2020-04-27 14:37:46 +0100170 ManifestDtBuilder &Description(const std::string_view &value)
171 {
172 return StringProperty("description", value);
173 }
174
David Brazdil52256ff2019-08-23 15:15:15 +0100175 ManifestDtBuilder &KernelFilename(const std::string_view &value)
176 {
177 return StringProperty("kernel_filename", value);
178 }
179
David Brazdile6f83222019-09-23 14:47:37 +0100180 ManifestDtBuilder &RamdiskFilename(const std::string_view &value)
181 {
182 return StringProperty("ramdisk_filename", value);
183 }
184
David Brazdil080ee312020-02-25 15:30:30 -0800185 ManifestDtBuilder &BootAddress(uint64_t value)
186 {
187 return Integer64Property("boot_address", value);
188 }
189
Andrew Scullae9962e2019-10-03 16:51:16 +0100190 ManifestDtBuilder &VcpuCount(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100191 {
192 return IntegerProperty("vcpu_count", value);
193 }
194
Andrew Scullae9962e2019-10-03 16:51:16 +0100195 ManifestDtBuilder &MemSize(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100196 {
197 return IntegerProperty("mem_size", value);
198 }
199
Andrew Scullae9962e2019-10-03 16:51:16 +0100200 ManifestDtBuilder &SmcWhitelist(const std::vector<uint32_t> &value)
201 {
202 return IntegerListProperty("smc_whitelist", value);
203 }
204
205 ManifestDtBuilder &SmcWhitelistPermissive()
206 {
207 return BooleanProperty("smc_whitelist_permissive");
208 }
209
Olivier Deprez62d99e32020-01-09 15:58:07 +0100210 ManifestDtBuilder &LoadAddress(uint64_t value)
211 {
212 return Integer64Property("load_address", value);
213 }
214
215 ManifestDtBuilder &FfaPartition()
216 {
217 return BooleanProperty("is_ffa_partition");
218 }
219
Andrew Scullae9962e2019-10-03 16:51:16 +0100220 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
Manish Pandeyfa1f2912020-05-05 12:57:01 +0100227 ManifestDtBuilder &Label(const std::string_view &name)
228 {
229 dts_ << name << ": ";
230 return *this;
231 }
232
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100233 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>");
J-Alves2f86c1e2022-02-23 18:44:19 +0000242 Property("entrypoint-offset", "<0x00002000>");
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100243 Property("xlat-granule", "<0>");
J-Alvesb37fd082020-10-22 12:29:21 +0100244 Property("boot-order", "<0>");
Maksims Svecovsb596eab2021-04-27 00:52:27 +0100245 Property("messaging-method", "<4>");
Madhukar Pappireddy84154052022-06-21 18:30:25 -0500246 Property("ns-interrupts-action", "<1>");
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100247 return *this;
248 }
249
David Brazdil52256ff2019-08-23 15:15:15 +0100250 private:
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
David Brazdil74e9c3b2019-08-28 11:09:08 +0100258 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
David Brazdil52256ff2019-08-23 15:15:15 +0100277 ManifestDtBuilder &IntegerProperty(const std::string_view &name,
Andrew Scullae9962e2019-10-03 16:51:16 +0100278 uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100279 {
280 dts_ << name << " = <" << value << ">;" << std::endl;
281 return *this;
282 }
283
David Brazdil080ee312020-02-25 15:30:30 -0800284 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
Andrew Scullae9962e2019-10-03 16:51:16 +0100294 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
306 ManifestDtBuilder &BooleanProperty(const std::string_view &name)
307 {
Andrew Scull5dc089e2019-11-04 13:21:03 +0000308 dts_ << name << ";" << std::endl;
309 return *this;
Andrew Scullae9962e2019-10-03 16:51:16 +0100310 }
311
David Brazdil52256ff2019-08-23 15:15:15 +0100312 std::stringstream dts_;
313};
314
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100315class manifest : public ::testing::Test
David Brazdil0dbb41f2019-09-09 18:03:35 +0100316{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100317 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
324 std::unique_ptr<uint8_t[]> test_heap;
325
326 protected:
Olivier Deprez62d99e32020-01-09 15:58:07 +0100327 struct mpool ppool;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100328
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100329 public:
330 /**
331 * Class for programatically building a Partition package.
332 */
333 class Partition_package
334 {
335 public:
336 __attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
337 __attribute__((
338 aligned(PAGE_SIZE))) char manifest_dtb[PAGE_SIZE] = {};
339 __attribute__((aligned(PAGE_SIZE))) char img[PAGE_SIZE] = {};
David Brazdil0dbb41f2019-09-09 18:03:35 +0100340
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100341 Partition_package(const std::vector<char> &vec)
342 {
343 // Initialise header field
344 spkg.magic = SP_PKG_HEADER_MAGIC;
345 spkg.version = SP_PKG_HEADER_VERSION_2;
346 spkg.pm_offset = PAGE_SIZE;
347 spkg.pm_size = vec.size();
348 spkg.img_offset = 2 * PAGE_SIZE;
349 spkg.img_size = ARRAY_SIZE(img);
350
351 // Copy dtb into package
352 std::copy(vec.begin(), vec.end(), manifest_dtb);
353 }
354 };
355
356 enum manifest_return_code manifest_from_vec(
357 struct_manifest *m, const std::vector<char> &vec)
358 {
359 struct memiter it;
360 struct mm_stage1_locked mm_stage1_locked;
361 enum manifest_return_code ret;
362
363 memiter_init(&it, vec.data(), vec.size());
364 ret = manifest_init(mm_stage1_locked, m, &it, &ppool);
365
366 manifest_deinit(&ppool);
367 return ret;
368 }
369
370 enum manifest_return_code ffa_manifest_from_vec(
371 struct_manifest *m, const std::vector<char> &vec)
372 {
373 struct memiter it;
374 struct mm_stage1_locked mm_stage1_locked;
375 enum manifest_return_code ret;
376
377 Partition_package spkg(vec);
378
379 /* clang-format off */
380 std::vector<char> core_dtb = ManifestDtBuilder()
381 .StartChild("hypervisor")
382 .Compatible()
383 .StartChild("vm1")
384 .DebugName("primary_vm")
385 .FfaPartition()
386 .LoadAddress((uint64_t)&spkg)
387 .EndChild()
388 .EndChild()
389 .Build();
390 /* clang-format on */
391 memiter_init(&it, core_dtb.data(), core_dtb.size());
392 ret = manifest_init(mm_stage1_locked, m, &it, &ppool);
393
394 manifest_deinit(&ppool);
395 return ret;
396 }
397};
398
399TEST_F(manifest, no_hypervisor_node)
David Brazdil7a462ec2019-08-15 12:27:47 +0100400{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100401 struct_manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100402 std::vector<char> dtb = ManifestDtBuilder().Build();
David Brazdil7a462ec2019-08-15 12:27:47 +0100403
David Brazdila2358d42020-01-27 18:51:38 +0000404 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil7a462ec2019-08-15 12:27:47 +0100405 MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
406}
407
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100408TEST_F(manifest, no_compatible_property)
David Brazdil7a462ec2019-08-15 12:27:47 +0100409{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100410 struct_manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100411
David Brazdil52256ff2019-08-23 15:15:15 +0100412 /* clang-format off */
413 std::vector<char> dtb = ManifestDtBuilder()
414 .StartChild("hypervisor")
415 .EndChild()
416 .Build();
417 /* clang-format on */
418
David Brazdilf4925382020-03-25 13:33:51 +0000419 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil7a462ec2019-08-15 12:27:47 +0100420}
421
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100422TEST_F(manifest, not_compatible)
David Brazdil7a462ec2019-08-15 12:27:47 +0100423{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100424 struct_manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100425
David Brazdil52256ff2019-08-23 15:15:15 +0100426 /* clang-format off */
427 std::vector<char> dtb = ManifestDtBuilder()
428 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100429 .Compatible({ "foo,bar" })
430 .EndChild()
431 .Build();
432 /* clang-format on */
433
David Brazdila2358d42020-01-27 18:51:38 +0000434 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100435}
436
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100437TEST_F(manifest, compatible_one_of_many)
David Brazdil74e9c3b2019-08-28 11:09:08 +0100438{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100439 struct_manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100440
441 /* clang-format off */
442 std::vector<char> dtb = ManifestDtBuilder()
443 .StartChild("hypervisor")
444 .Compatible({ "foo,bar", "hafnium,hafnium" })
445 .StartChild("vm1")
446 .DebugName("primary")
447 .EndChild()
448 .EndChild()
449 .Build();
450 /* clang-format on */
451
David Brazdila2358d42020-01-27 18:51:38 +0000452 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100453}
454
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100455TEST_F(manifest, no_vm_nodes)
David Brazdil74e9c3b2019-08-28 11:09:08 +0100456{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100457 struct_manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100458
459 /* clang-format off */
460 std::vector<char> dtb = ManifestDtBuilder()
461 .StartChild("hypervisor")
462 .Compatible()
463 .EndChild()
464 .Build();
465 /* clang-format on */
466
David Brazdila2358d42020-01-27 18:51:38 +0000467 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NO_PRIMARY_VM);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100468}
469
470static std::vector<char> gen_long_string_dtb(bool valid)
471{
472 const char last_valid[] = "1234567890123456789012345678901";
473 const char first_invalid[] = "12345678901234567890123456789012";
David Brazdil136f2942019-09-23 14:11:03 +0100474 static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
475 static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100476
477 /* clang-format off */
478 return ManifestDtBuilder()
479 .StartChild("hypervisor")
480 .Compatible()
481 .StartChild("vm1")
482 .DebugName(valid ? last_valid : first_invalid)
483 .EndChild()
484 .EndChild()
485 .Build();
486 /* clang-format on */
487}
488
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100489TEST_F(manifest, long_string)
David Brazdil0dbb41f2019-09-09 18:03:35 +0100490{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100491 struct_manifest m;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100492 std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
493 std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
494
David Brazdila2358d42020-01-27 18:51:38 +0000495 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
496 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
497 MANIFEST_ERROR_STRING_TOO_LONG);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100498}
499
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100500TEST_F(manifest, reserved_vm_id)
David Brazdil74e9c3b2019-08-28 11:09:08 +0100501{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100502 struct_manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100503
504 /* clang-format off */
505 std::vector<char> dtb = ManifestDtBuilder()
506 .StartChild("hypervisor")
507 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100508 .StartChild("vm1")
509 .DebugName("primary_vm")
510 .EndChild()
511 .StartChild("vm0")
512 .DebugName("reserved_vm")
513 .VcpuCount(1)
514 .MemSize(0x1000)
515 .KernelFilename("kernel")
516 .EndChild()
517 .EndChild()
518 .Build();
519 /* clang-format on */
520
David Brazdila2358d42020-01-27 18:51:38 +0000521 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_RESERVED_VM_ID);
David Brazdil7a462ec2019-08-15 12:27:47 +0100522}
523
Andrew Scullae9962e2019-10-03 16:51:16 +0100524static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
David Brazdil52256ff2019-08-23 15:15:15 +0100525{
526 /* clang-format off */
527 return ManifestDtBuilder()
528 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100529 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100530 .StartChild("vm1")
531 .DebugName("primary_vm")
532 .EndChild()
533 .StartChild("vm2")
534 .DebugName("secondary_vm")
535 .VcpuCount(vcpu_count)
536 .MemSize(0x1000)
537 .KernelFilename("kernel")
538 .EndChild()
539 .EndChild()
540 .Build();
541 /* clang-format on */
542}
David Brazdil7a462ec2019-08-15 12:27:47 +0100543
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100544TEST_F(manifest, vcpu_count_limit)
David Brazdil7a462ec2019-08-15 12:27:47 +0100545{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100546 struct_manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100547 std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
548 std::vector<char> dtb_first_invalid =
549 gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
David Brazdil7a462ec2019-08-15 12:27:47 +0100550
David Brazdila2358d42020-01-27 18:51:38 +0000551 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100552 ASSERT_EQ(m.vm_count, 2);
David Brazdil7a462ec2019-08-15 12:27:47 +0100553 ASSERT_EQ(m.vm[1].secondary.vcpu_count, UINT16_MAX);
554
David Brazdila2358d42020-01-27 18:51:38 +0000555 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100556 MANIFEST_ERROR_INTEGER_OVERFLOW);
David Brazdil7a462ec2019-08-15 12:27:47 +0100557}
558
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100559TEST_F(manifest, no_ramdisk_primary)
David Brazdile6f83222019-09-23 14:47:37 +0100560{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100561 struct_manifest m;
David Brazdile6f83222019-09-23 14:47:37 +0100562
563 /* clang-format off */
564 std::vector<char> dtb = ManifestDtBuilder()
565 .StartChild("hypervisor")
566 .Compatible()
567 .StartChild("vm1")
568 .DebugName("primary_vm")
569 .EndChild()
570 .EndChild()
571 .Build();
572 /* clang-format on */
573
David Brazdila2358d42020-01-27 18:51:38 +0000574 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdile6f83222019-09-23 14:47:37 +0100575 ASSERT_EQ(m.vm_count, 1);
576 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
577 ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
578}
579
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100580TEST_F(manifest, no_boot_address_primary)
David Brazdil080ee312020-02-25 15:30:30 -0800581{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100582 struct_manifest m;
David Brazdil080ee312020-02-25 15:30:30 -0800583
584 /* clang-format off */
585 std::vector<char> dtb = ManifestDtBuilder()
586 .StartChild("hypervisor")
587 .Compatible()
588 .StartChild("vm1")
589 .DebugName("primary_vm")
590 .EndChild()
591 .EndChild()
592 .Build();
593 /* clang-format on */
594
595 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
596 ASSERT_EQ(m.vm_count, 1);
597 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
598 ASSERT_EQ(m.vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
599}
600
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100601TEST_F(manifest, boot_address_primary)
David Brazdil080ee312020-02-25 15:30:30 -0800602{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100603 struct_manifest m;
David Brazdil080ee312020-02-25 15:30:30 -0800604 const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
605
606 /* clang-format off */
607 std::vector<char> dtb = ManifestDtBuilder()
608 .StartChild("hypervisor")
609 .Compatible()
610 .StartChild("vm1")
611 .DebugName("primary_vm")
612 .BootAddress(addr)
613 .EndChild()
614 .EndChild()
615 .Build();
616 /* clang-format on */
617
618 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
619 ASSERT_EQ(m.vm_count, 1);
620 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
621 ASSERT_EQ(m.vm[0].primary.boot_address, addr);
622}
623
Andrew Scullb2c3a242019-11-04 13:52:36 +0000624static std::vector<char> gen_malformed_boolean_dtb(
625 const std::string_view &value)
Andrew Scullae9962e2019-10-03 16:51:16 +0100626{
Andrew Scullae9962e2019-10-03 16:51:16 +0100627 /* clang-format off */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000628 return ManifestDtBuilder()
Andrew Scullae9962e2019-10-03 16:51:16 +0100629 .StartChild("hypervisor")
630 .Compatible()
631 .StartChild("vm1")
632 .DebugName("primary_vm")
Andrew Scullb2c3a242019-11-04 13:52:36 +0000633 .Property("smc_whitelist_permissive", value)
Andrew Scull5dc089e2019-11-04 13:21:03 +0000634 .EndChild()
Andrew Scullae9962e2019-10-03 16:51:16 +0100635 .EndChild()
636 .Build();
637 /* clang-format on */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000638}
Andrew Scullae9962e2019-10-03 16:51:16 +0100639
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100640TEST_F(manifest, malformed_booleans)
Andrew Scullb2c3a242019-11-04 13:52:36 +0000641{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100642 struct_manifest m;
Andrew Scullae9962e2019-10-03 16:51:16 +0100643
Andrew Scullb2c3a242019-11-04 13:52:36 +0000644 std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
645 std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
646 std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
647 std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
Andrew Scullae9962e2019-10-03 16:51:16 +0100648
David Brazdila2358d42020-01-27 18:51:38 +0000649 ASSERT_EQ(manifest_from_vec(&m, dtb_false),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000650 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000651 ASSERT_EQ(manifest_from_vec(&m, dtb_true),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000652 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000653 ASSERT_EQ(manifest_from_vec(&m, dtb_0),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000654 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000655 ASSERT_EQ(manifest_from_vec(&m, dtb_1),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000656 MANIFEST_ERROR_MALFORMED_BOOLEAN);
Andrew Scullae9962e2019-10-03 16:51:16 +0100657}
658
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100659TEST_F(manifest, valid)
David Brazdil7a462ec2019-08-15 12:27:47 +0100660{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100661 struct_manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100662 struct manifest_vm *vm;
David Brazdil7a462ec2019-08-15 12:27:47 +0100663
David Brazdil52256ff2019-08-23 15:15:15 +0100664 /* clang-format off */
665 std::vector<char> dtb = ManifestDtBuilder()
666 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100667 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100668 .StartChild("vm1")
669 .DebugName("primary_vm")
Andrew Scull72b43c02019-09-18 13:53:45 +0100670 .KernelFilename("primary_kernel")
David Brazdile6f83222019-09-23 14:47:37 +0100671 .RamdiskFilename("primary_ramdisk")
Andrew Scullae9962e2019-10-03 16:51:16 +0100672 .SmcWhitelist({0x32000000, 0x33001111})
David Brazdil52256ff2019-08-23 15:15:15 +0100673 .EndChild()
674 .StartChild("vm3")
675 .DebugName("second_secondary_vm")
676 .VcpuCount(43)
677 .MemSize(0x12345)
Andrew Scull72b43c02019-09-18 13:53:45 +0100678 .KernelFilename("second_secondary_kernel")
David Brazdil52256ff2019-08-23 15:15:15 +0100679 .EndChild()
680 .StartChild("vm2")
681 .DebugName("first_secondary_vm")
682 .VcpuCount(42)
683 .MemSize(12345)
Andrew Scullae9962e2019-10-03 16:51:16 +0100684 .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
685 .SmcWhitelistPermissive()
David Brazdil52256ff2019-08-23 15:15:15 +0100686 .EndChild()
687 .EndChild()
688 .Build();
689 /* clang-format on */
690
David Brazdila2358d42020-01-27 18:51:38 +0000691 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100692 ASSERT_EQ(m.vm_count, 3);
David Brazdil7a462ec2019-08-15 12:27:47 +0100693
694 vm = &m.vm[0];
David Brazdil136f2942019-09-23 14:11:03 +0100695 ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
696 ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
David Brazdile6f83222019-09-23 14:47:37 +0100697 ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
698 "primary_ramdisk");
Andrew Scullae9962e2019-10-03 16:51:16 +0100699 ASSERT_THAT(
700 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
701 ElementsAre(0x32000000, 0x33001111));
702 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100703
704 vm = &m.vm[1];
David Brazdil136f2942019-09-23 14:11:03 +0100705 ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
706 ASSERT_STREQ(string_data(&vm->kernel_filename), "");
David Brazdil7a462ec2019-08-15 12:27:47 +0100707 ASSERT_EQ(vm->secondary.vcpu_count, 42);
708 ASSERT_EQ(vm->secondary.mem_size, 12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100709 ASSERT_THAT(
710 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
711 ElementsAre(0x04000000, 0x30002222, 0x31445566));
712 ASSERT_TRUE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100713
714 vm = &m.vm[2];
David Brazdil136f2942019-09-23 14:11:03 +0100715 ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
716 ASSERT_STREQ(string_data(&vm->kernel_filename),
717 "second_secondary_kernel");
David Brazdil7a462ec2019-08-15 12:27:47 +0100718 ASSERT_EQ(vm->secondary.vcpu_count, 43);
719 ASSERT_EQ(vm->secondary.mem_size, 0x12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100720 ASSERT_THAT(
721 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
722 IsEmpty());
723 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100724}
725
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100726TEST_F(manifest, ffa_not_compatible)
Olivier Deprez62d99e32020-01-09 15:58:07 +0100727{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100728 struct_manifest m;
Olivier Deprez62d99e32020-01-09 15:58:07 +0100729
730 /* clang-format off */
731 std::vector<char> dtb = ManifestDtBuilder()
732 .Compatible({ "arm,ffa-manifest-2.0" })
733 .Property("ffa-version", "<0x10000>")
734 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
735 .Property("execution-ctx-count", "<1>")
736 .Property("exception-level", "<2>")
737 .Property("execution-state", "<0>")
J-Alves2f86c1e2022-02-23 18:44:19 +0000738 .Property("entrypoint-offset", "<0x00002000>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100739 .Property("xlat-granule", "<0>")
740 .Property("messaging-method", "<1>")
Madhukar Pappireddy84154052022-06-21 18:30:25 -0500741 .Property("ns-interrupts-action", "<1>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100742 .Build();
743 /* clang-format on */
744
745 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
746 MANIFEST_ERROR_NOT_COMPATIBLE);
747}
748
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100749TEST_F(manifest, ffa_missing_property)
Olivier Deprez62d99e32020-01-09 15:58:07 +0100750{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100751 struct_manifest m;
Olivier Deprez62d99e32020-01-09 15:58:07 +0100752
753 /* clang-format off */
754 std::vector<char> dtb = ManifestDtBuilder()
755 .Compatible({ "arm,ffa-manifest-1.0" })
756 .Property("ffa-version", "<0x10000>")
757 .Build();
758 /* clang-format on */
759
760 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
761 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
762}
763
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100764TEST_F(manifest, ffa_validate_sanity_check)
Olivier Deprez62d99e32020-01-09 15:58:07 +0100765{
J-Alvesb37fd082020-10-22 12:29:21 +0100766 /*
767 * TODO: write test excluding all optional fields of the manifest, in
768 * accordance with specification.
769 */
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100770 struct_manifest m;
Olivier Deprez62d99e32020-01-09 15:58:07 +0100771
772 /* Incompatible version */
773 /* clang-format off */
774 std::vector<char> dtb = ManifestDtBuilder()
775 .Compatible({ "arm,ffa-manifest-1.0" })
776 .Property("ffa-version", "<0xa1>")
777 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
778 .Property("execution-ctx-count", "<1>")
779 .Property("exception-level", "<2>")
780 .Property("execution-state", "<0>")
J-Alves2f86c1e2022-02-23 18:44:19 +0000781 .Property("entrypoint-offset", "<0x00002000>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100782 .Property("xlat-granule", "<0>")
J-Alvesb37fd082020-10-22 12:29:21 +0100783 .Property("boot-order", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100784 .Property("messaging-method", "<1>")
Madhukar Pappireddy84154052022-06-21 18:30:25 -0500785 .Property("ns-interrupts-action", "<1>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100786 .Build();
787 /* clang-format on */
788 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
789 MANIFEST_ERROR_NOT_COMPATIBLE);
790
791 /* Incompatible translation granule */
792 /* clang-format off */
793 dtb = ManifestDtBuilder()
794 .Compatible({ "arm,ffa-manifest-1.0" })
795 .Property("ffa-version", "<0x10000>")
796 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
797 .Property("execution-ctx-count", "<1>")
798 .Property("exception-level", "<2>")
799 .Property("execution-state", "<0>")
J-Alves2f86c1e2022-02-23 18:44:19 +0000800 .Property("entrypoint-offset", "<0x00002000>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100801 .Property("xlat-granule", "<3>")
J-Alvesb37fd082020-10-22 12:29:21 +0100802 .Property("boot-order", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100803 .Property("messaging-method", "<1>")
Madhukar Pappireddy84154052022-06-21 18:30:25 -0500804 .Property("ns-interrupts-action", "<1>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100805 .Build();
806 /* clang-format on */
807 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
808 MANIFEST_ERROR_NOT_COMPATIBLE);
809
810 /* Incompatible exeption level */
811 /* clang-format off */
812 dtb = ManifestDtBuilder()
813 .Compatible({ "arm,ffa-manifest-1.0" })
814 .Property("ffa-version", "<0x10000>")
815 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
816 .Property("execution-ctx-count", "<1>")
817 .Property("exception-level", "<6>")
818 .Property("execution-state", "<0>")
J-Alves2f86c1e2022-02-23 18:44:19 +0000819 .Property("entrypoint-offset", "<0x00002000>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100820 .Property("xlat-granule", "<0>")
J-Alvesb37fd082020-10-22 12:29:21 +0100821 .Property("boot-order", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100822 .Property("messaging-method", "<1>")
Madhukar Pappireddy84154052022-06-21 18:30:25 -0500823 .Property("ns-interrupts-action", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100824 .Build();
825 /* clang-format on */
826 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
827 MANIFEST_ERROR_NOT_COMPATIBLE);
828
829 /* Incompatible execution state */
830 /* clang-format off */
831 dtb = ManifestDtBuilder()
832 .Compatible({ "arm,ffa-manifest-1.0" })
833 .Property("ffa-version", "<0x10000>")
834 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
835 .Property("execution-ctx-count", "<1>")
836 .Property("exception-level", "<2>")
837 .Property("execution-state", "<2>")
J-Alves2f86c1e2022-02-23 18:44:19 +0000838 .Property("entrypoint-offset", "<0x00002000>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100839 .Property("xlat-granule", "<0>")
J-Alvesb37fd082020-10-22 12:29:21 +0100840 .Property("boot-order", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100841 .Property("messaging-method", "<1>")
Madhukar Pappireddy84154052022-06-21 18:30:25 -0500842 .Property("ns-interrupts-action", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100843 .Build();
844 /* clang-format on */
845 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
846 MANIFEST_ERROR_NOT_COMPATIBLE);
847
848 /* Incompatible messaging method */
849 /* clang-format off */
850 dtb = ManifestDtBuilder()
851 .Compatible({ "arm,ffa-manifest-1.0" })
852 .Property("ffa-version", "<0x10000>")
853 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
854 .Property("execution-ctx-count", "<1>")
855 .Property("exception-level", "<2>")
856 .Property("execution-state", "<0>")
J-Alves2f86c1e2022-02-23 18:44:19 +0000857 .Property("entrypoint-offset", "<0x00002000>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100858 .Property("xlat-granule", "<0>")
J-Alvesb37fd082020-10-22 12:29:21 +0100859 .Property("boot-order", "<0>")
Maksims Svecovsb596eab2021-04-27 00:52:27 +0100860 .Property("messaging-method", "<16>")
Madhukar Pappireddy84154052022-06-21 18:30:25 -0500861 .Property("ns-interrupts-action", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100862 .Build();
863 /* clang-format on */
864 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
865 MANIFEST_ERROR_NOT_COMPATIBLE);
Madhukar Pappireddy84154052022-06-21 18:30:25 -0500866
867 /* Incompatible NS interrupt action */
868 /* clang-format off */
869 dtb = ManifestDtBuilder()
870 .Compatible({ "arm,ffa-manifest-1.0" })
871 .Property("ffa-version", "<0x10000>")
872 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
873 .Property("execution-ctx-count", "<1>")
874 .Property("exception-level", "<2>")
875 .Property("execution-state", "<0>")
876 .Property("entrypoint-offset", "<0x00002000>")
877 .Property("xlat-granule", "<0>")
878 .Property("boot-order", "<0>")
879 .Property("messaging-method", "<1>")
880 .Property("ns-interrupts-action", "<4>")
881 .Build();
882 /* clang-format on */
883 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_ILLEGAL_NS_ACTION);
Olivier Deprez62d99e32020-01-09 15:58:07 +0100884}
885
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100886TEST_F(manifest, ffa_validate_rxtx_info)
Manish Pandeyfa1f2912020-05-05 12:57:01 +0100887{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100888 struct_manifest m;
Manish Pandeyfa1f2912020-05-05 12:57:01 +0100889
890 /* Not Compatible */
891 /* clang-format off */
892 std::vector<char> dtb = ManifestDtBuilder()
893 .FfaValidManifest()
894 .StartChild("rx_tx-info")
895 .Compatible({ "foo,bar" })
896 .EndChild()
897 .Build();
898 /* clang-format on */
899 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
900 MANIFEST_ERROR_NOT_COMPATIBLE);
901
902 /* Missing Properties */
903 /* clang-format off */
904 dtb = ManifestDtBuilder()
905 .FfaValidManifest()
906 .StartChild("rx_tx-info")
907 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
908 .EndChild()
909 .Build();
910 /* clang-format on */
911 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
912 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
913}
914
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100915TEST_F(manifest, ffa_validate_mem_regions)
Manish Pandey6542f5c2020-04-27 14:37:46 +0100916{
Daniel Boulby801f8ef2022-06-27 14:21:01 +0100917 struct_manifest m;
Manish Pandey6542f5c2020-04-27 14:37:46 +0100918
919 /* Not Compatible */
920 /* clang-format off */
921 std::vector<char> dtb = ManifestDtBuilder()
922 .FfaValidManifest()
923 .StartChild("memory-regions")
924 .Compatible({ "foo,bar" })
925 .EndChild()
926 .Build();
927 /* clang-format on */
928 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
929 MANIFEST_ERROR_NOT_COMPATIBLE);
930
931 /* Memory regions unavailable */
932 /* clang-format off */
933 dtb = ManifestDtBuilder()
934 .FfaValidManifest()
935 .StartChild("memory-regions")
936 .Compatible({ "arm,ffa-manifest-memory-regions" })
937 .EndChild()
938 .Build();
939 /* clang-format on */
940 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
941 MANIFEST_ERROR_MEMORY_REGION_NODE_EMPTY);
942
943 /* Missing Properties */
944 /* clang-format off */
945 dtb = ManifestDtBuilder()
946 .FfaValidManifest()
947 .StartChild("memory-regions")
948 .Compatible({ "arm,ffa-manifest-memory-regions" })
949 .StartChild("test-memory")
950 .Description("test-memory")
951 .EndChild()
952 .EndChild()
953 .Build();
954 /* clang-format on */
955 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
956 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
Manish Pandeyf06c9072020-09-29 15:41:58 +0100957
Daniel Boulby9279b552022-06-28 17:04:01 +0100958 /* Overlapping memory regions */
959 /* clang-format off */
960 dtb = ManifestDtBuilder()
961 .FfaValidManifest()
962 .StartChild("memory-regions")
963 .Compatible({ "arm,ffa-manifest-memory-regions" })
964 .Label("rx")
965 .StartChild("rx")
966 .Description("rx-buffer")
967 .Property("base-address", "<0x7300000>")
968 .Property("pages-count", "<1>")
969 .Property("attributes", "<1>")
970 .EndChild()
971 .Label("tx")
972 .StartChild("tx")
973 .Description("tx-buffer")
974 .Property("base-address", "<0x7300000>")
975 .Property("pages-count", "<2>")
976 .Property("attributes", "<3>")
977 .EndChild()
978 .EndChild()
979 .Build();
980 /* clang-format on */
981 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
982 MANIFEST_ERROR_MEM_REGION_OVERLAP);
983
984 /* clang-format off */
985 dtb = ManifestDtBuilder()
986 .FfaValidManifest()
987 .StartChild("memory-regions")
988 .Compatible({ "arm,ffa-manifest-memory-regions" })
989 .Label("rx")
990 .StartChild("rx")
991 .Description("rx-buffer")
992 .Property("base-address", "<0x7300000>")
993 .Property("pages-count", "<2>")
994 .Property("attributes", "<1>")
995 .EndChild()
996 .Label("tx")
997 .StartChild("tx")
998 .Description("tx-buffer")
999 .Property("base-address", "<0x7301000>")
1000 .Property("pages-count", "<2>")
1001 .Property("attributes", "<3>")
1002 .EndChild()
1003 .EndChild()
1004 .Build();
1005 /* clang-format on */
1006 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1007 MANIFEST_ERROR_MEM_REGION_OVERLAP);
1008
1009 /* clang-format off */
1010 dtb = ManifestDtBuilder()
1011 .FfaValidManifest()
1012 .StartChild("memory-regions")
1013 .Compatible({ "arm,ffa-manifest-memory-regions" })
1014 .Label("rx")
1015 .StartChild("rx")
1016 .Description("rx-buffer")
1017 .Property("base-address", "<0x7300000>")
1018 .Property("pages-count", "<2>")
1019 .Property("attributes", "<1>")
1020 .EndChild()
1021 .Label("tx")
1022 .StartChild("tx")
1023 .Description("tx-buffer")
1024 .Property("base-address", "<0x7301FFF>")
1025 .Property("pages-count", "<2>")
1026 .Property("attributes", "<3>")
1027 .EndChild()
1028 .EndChild()
1029 .Build();
1030 /* clang-format on */
1031 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1032 MANIFEST_ERROR_MEM_REGION_OVERLAP);
1033
Manish Pandeyf06c9072020-09-29 15:41:58 +01001034 /* Different RXTX buffer sizes */
1035 /* clang-format off */
1036 dtb = ManifestDtBuilder()
1037 .FfaValidManifest()
1038 .StartChild("memory-regions")
1039 .Compatible({ "arm,ffa-manifest-memory-regions" })
1040 .Label("rx")
1041 .StartChild("rx")
1042 .Description("rx-buffer")
1043 .Property("base-address", "<0x7300000>")
1044 .Property("pages-count", "<1>")
1045 .Property("attributes", "<1>")
1046 .EndChild()
1047 .Label("tx")
1048 .StartChild("tx")
1049 .Description("tx-buffer")
1050 .Property("base-address", "<0x7310000>")
1051 .Property("pages-count", "<2>")
1052 .Property("attributes", "<3>")
1053 .EndChild()
1054 .EndChild()
1055 .StartChild("rx_tx-info")
1056 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1057 .Property("rx-buffer", "<&rx>")
1058 .Property("tx-buffer", "<&tx>")
1059 .EndChild()
1060 .Build();
1061 /* clang-format on */
1062 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1063 MANIFEST_ERROR_RXTX_SIZE_MISMATCH);
Manish Pandey6542f5c2020-04-27 14:37:46 +01001064}
1065
Daniel Boulby801f8ef2022-06-27 14:21:01 +01001066TEST_F(manifest, ffa_validate_dev_regions)
Manish Pandeye68e7932020-04-23 15:29:28 +01001067{
Daniel Boulby801f8ef2022-06-27 14:21:01 +01001068 struct_manifest m;
Manish Pandeye68e7932020-04-23 15:29:28 +01001069
1070 /* Not Compatible */
1071 /* clang-format off */
1072 std::vector<char> dtb = ManifestDtBuilder()
1073 .FfaValidManifest()
1074 .StartChild("device-regions")
1075 .Compatible({ "foo,bar" })
1076 .EndChild()
1077 .Build();
1078 /* clang-format on */
1079 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1080 MANIFEST_ERROR_NOT_COMPATIBLE);
1081
1082 /* Memory regions unavailable */
1083 /* clang-format off */
1084 dtb = ManifestDtBuilder()
1085 .FfaValidManifest()
1086 .StartChild("device-regions")
1087 .Compatible({ "arm,ffa-manifest-device-regions" })
1088 .EndChild()
1089 .Build();
1090 /* clang-format on */
1091 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1092 MANIFEST_ERROR_DEVICE_REGION_NODE_EMPTY);
1093
1094 /* Missing Properties */
1095 /* clang-format off */
1096 dtb = ManifestDtBuilder()
1097 .FfaValidManifest()
1098 .StartChild("device-regions")
1099 .Compatible({ "arm,ffa-manifest-device-regions" })
1100 .StartChild("test-device")
1101 .Description("test-device")
1102 .EndChild()
1103 .EndChild()
1104 .Build();
1105 /* clang-format on */
1106 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1107 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
1108
1109 /* Malformed interrupt list pair */
1110 /* clang-format off */
1111 dtb = ManifestDtBuilder()
1112 .FfaValidManifest()
1113 .StartChild("device-regions")
1114 .Compatible({ "arm,ffa-manifest-device-regions" })
1115 .StartChild("test-device")
1116 .Description("test-device")
1117 .Property("base-address", "<0x7200000>")
1118 .Property("pages-count", "<16>")
1119 .Property("attributes", "<3>")
1120 .Property("smmu-id", "<1>")
1121 .Property("stream-ids", "<0 1>")
1122 .Property("interrupts", "<2 3>, <4>")
1123 .EndChild()
1124 .EndChild()
1125 .Build();
1126 /* clang-format on */
1127 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1128 MANIFEST_ERROR_MALFORMED_INTEGER_LIST);
Daniel Boulby667334f2022-06-27 15:23:21 +01001129
1130 /* Non-unique interrupt IDs */
1131 /* clang-format off */
1132 dtb = ManifestDtBuilder()
1133 .FfaValidManifest()
1134 .StartChild("device-regions")
1135 .Compatible({ "arm,ffa-manifest-device-regions" })
1136 .StartChild("test-device-0")
1137 .Description("test-device-0")
1138 .Property("base-address", "<0x7200000>")
1139 .Property("pages-count", "<16>")
1140 .Property("attributes", "<3>")
1141 .Property("interrupts", "<2 3>")
1142 .EndChild()
1143 .StartChild("test-device-1")
1144 .Description("test-device-1")
1145 .Property("base-address", "<0x8200000>")
1146 .Property("pages-count", "<16>")
1147 .Property("attributes", "<3>")
1148 .Property("interrupts", "<1 3>, <2 5> ")
1149 .EndChild()
1150 .EndChild()
1151 .Build();
1152 /* clang-format on */
1153 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1154 MANIFEST_ERROR_INTERRUPT_ID_REPEATED);
1155 /* Check valid interrupts were still mapped */
1156 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[0].id, 2);
1157 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[0].attributes, 3);
1158 ASSERT_EQ(m.vm[0].partition.dev_regions[1].interrupts[0].id, 1);
1159 ASSERT_EQ(m.vm[0].partition.dev_regions[1].interrupts[0].attributes, 3);
Manish Pandeye68e7932020-04-23 15:29:28 +01001160}
Daniel Boulby801f8ef2022-06-27 14:21:01 +01001161
1162TEST_F(manifest, ffa_invalid_memory_region_attributes)
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -07001163{
Daniel Boulby801f8ef2022-06-27 14:21:01 +01001164 struct_manifest m;
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -07001165
1166 /* clang-format off */
1167 std::vector<char> dtb = ManifestDtBuilder()
1168 .FfaValidManifest()
1169 .StartChild("rx_tx-info")
1170 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1171 .Property("rx-buffer", "<&rx>")
1172 .Property("tx-buffer", "<&tx>")
1173 .EndChild()
1174 .StartChild("memory-regions")
1175 .Compatible({ "arm,ffa-manifest-memory-regions" })
1176 .StartChild("test-memory")
1177 .Description("test-memory")
1178 .Property("base-address", "<0x7100000>")
1179 .Property("pages-count", "<4>")
1180 .Property("attributes", "<7>")
1181 .EndChild()
1182 .Label("rx")
1183 .StartChild("rx")
1184 .Description("rx-buffer")
1185 .Property("base-address", "<0x7300000>")
1186 .Property("pages-count", "<1>")
1187 .Property("attributes", "<1>")
1188 .EndChild()
1189 .Label("tx")
1190 .StartChild("tx")
1191 .Description("tx-buffer")
1192 .Property("base-address", "<0x7310000>")
1193 .Property("pages-count", "<1>")
1194 .Property("attributes", "<3>")
1195 .EndChild()
1196 .EndChild()
1197 .Build();
1198 /* clang-format on */
1199
1200 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1201 MANIFEST_ERROR_INVALID_MEM_PERM);
1202}
1203
Daniel Boulby801f8ef2022-06-27 14:21:01 +01001204TEST_F(manifest, ffa_invalid_device_region_attributes)
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -07001205{
Daniel Boulby801f8ef2022-06-27 14:21:01 +01001206 struct_manifest m;
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -07001207
1208 /* clang-format off */
1209 std::vector<char> dtb = ManifestDtBuilder()
1210 .FfaValidManifest()
1211 .StartChild("rx_tx-info")
1212 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1213 .Property("rx-buffer", "<&rx>")
1214 .Property("tx-buffer", "<&tx>")
1215 .EndChild()
1216 .StartChild("memory-regions")
1217 .Compatible({ "arm,ffa-manifest-memory-regions" })
1218 .StartChild("test-memory")
1219 .Description("test-memory")
1220 .Property("base-address", "<0x7100000>")
1221 .Property("pages-count", "<4>")
1222 .Property("attributes", "<3>")
1223 .EndChild()
1224 .Label("rx")
1225 .StartChild("rx")
1226 .Description("rx-buffer")
1227 .Property("base-address", "<0x7300000>")
1228 .Property("pages-count", "<1>")
1229 .Property("attributes", "<1>")
1230 .EndChild()
1231 .Label("tx")
1232 .StartChild("tx")
1233 .Description("tx-buffer")
1234 .Property("base-address", "<0x7310000>")
1235 .Property("pages-count", "<1>")
1236 .Property("attributes", "<3>")
1237 .EndChild()
1238 .EndChild()
1239 .StartChild("device-regions")
1240 .Compatible({ "arm,ffa-manifest-device-regions" })
1241 .StartChild("test-device")
1242 .Description("test-device")
1243 .Property("base-address", "<0x7200000>")
1244 .Property("pages-count", "<16>")
1245 .Property("attributes", "<5>")
1246 .Property("smmu-id", "<1>")
1247 .Property("stream-ids", "<0 1>")
1248 .Property("interrupts", "<2 3>, <4 5>")
1249 .EndChild()
1250 .EndChild()
1251 .Build();
1252 /* clang-format on */
1253
1254 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1255 MANIFEST_ERROR_INVALID_MEM_PERM);
1256}
Manish Pandeye68e7932020-04-23 15:29:28 +01001257
Daniel Boulby801f8ef2022-06-27 14:21:01 +01001258TEST_F(manifest, ffa_valid)
Olivier Deprez62d99e32020-01-09 15:58:07 +01001259{
Daniel Boulby801f8ef2022-06-27 14:21:01 +01001260 struct_manifest m;
Olivier Deprez62d99e32020-01-09 15:58:07 +01001261
1262 /* clang-format off */
1263 std::vector<char> dtb = ManifestDtBuilder()
Manish Pandeycb8fbb22020-08-18 00:04:43 +01001264 .FfaValidManifest()
Manish Pandeyfa1f2912020-05-05 12:57:01 +01001265 .StartChild("rx_tx-info")
1266 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1267 .Property("rx-buffer", "<&rx>")
1268 .Property("tx-buffer", "<&tx>")
1269 .EndChild()
Manish Pandey6542f5c2020-04-27 14:37:46 +01001270 .StartChild("memory-regions")
1271 .Compatible({ "arm,ffa-manifest-memory-regions" })
1272 .StartChild("test-memory")
1273 .Description("test-memory")
1274 .Property("base-address", "<0x7100000>")
1275 .Property("pages-count", "<4>")
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -07001276 .Property("attributes", "<3>")
Manish Pandey6542f5c2020-04-27 14:37:46 +01001277 .EndChild()
Olivier Deprez035fa152022-03-14 11:19:10 +01001278 .StartChild("test-memory-ns")
1279 .Description("test-memory")
1280 .Property("base-address", "<0x7200000>")
1281 .Property("pages-count", "<1>")
1282 .Property("attributes", "<0xb>")
1283 .EndChild()
Manish Pandeyfa1f2912020-05-05 12:57:01 +01001284 .Label("rx")
1285 .StartChild("rx")
1286 .Description("rx-buffer")
1287 .Property("base-address", "<0x7300000>")
1288 .Property("pages-count", "<1>")
1289 .Property("attributes", "<1>")
1290 .EndChild()
1291 .Label("tx")
1292 .StartChild("tx")
1293 .Description("tx-buffer")
Daniel Boulby9279b552022-06-28 17:04:01 +01001294 .Property("base-address", "<0x7301000>")
Manish Pandeyfa1f2912020-05-05 12:57:01 +01001295 .Property("pages-count", "<1>")
1296 .Property("attributes", "<3>")
1297 .EndChild()
Manish Pandey6542f5c2020-04-27 14:37:46 +01001298 .EndChild()
Manish Pandeye68e7932020-04-23 15:29:28 +01001299 .StartChild("device-regions")
1300 .Compatible({ "arm,ffa-manifest-device-regions" })
1301 .StartChild("test-device")
1302 .Description("test-device")
Olivier Deprez035fa152022-03-14 11:19:10 +01001303 .Property("base-address", "<0x7400000>")
Manish Pandeye68e7932020-04-23 15:29:28 +01001304 .Property("pages-count", "<16>")
1305 .Property("attributes", "<3>")
1306 .Property("smmu-id", "<1>")
1307 .Property("stream-ids", "<0 1>")
1308 .Property("interrupts", "<2 3>, <4 5>")
1309 .EndChild()
Olivier Deprez035fa152022-03-14 11:19:10 +01001310 .StartChild("test-device-ns")
1311 .Description("test-device")
1312 .Property("base-address", "<0x7500000>")
1313 .Property("pages-count", "<1>")
1314 .Property("attributes", "<0x9>")
1315 .EndChild()
Manish Pandeye68e7932020-04-23 15:29:28 +01001316 .EndChild()
Olivier Deprez62d99e32020-01-09 15:58:07 +01001317 .Build();
1318 /* clang-format on */
1319
1320 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
1321
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001322 ASSERT_EQ(m.vm[0].partition.ffa_version, 0x10000);
Olivier Deprez62d99e32020-01-09 15:58:07 +01001323 ASSERT_THAT(
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001324 std::span(m.vm[0].partition.uuid.uuid, 4),
Olivier Deprez62d99e32020-01-09 15:58:07 +01001325 ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb));
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001326 ASSERT_EQ(m.vm[0].partition.execution_ctx_count, 1);
1327 ASSERT_EQ(m.vm[0].partition.run_time_el, S_EL1);
1328 ASSERT_EQ(m.vm[0].partition.execution_state, AARCH64);
J-Alves2f86c1e2022-02-23 18:44:19 +00001329 ASSERT_EQ(m.vm[0].partition.ep_offset, 0x00002000);
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001330 ASSERT_EQ(m.vm[0].partition.xlat_granule, PAGE_4KB);
1331 ASSERT_EQ(m.vm[0].partition.boot_order, 0);
1332 ASSERT_EQ(m.vm[0].partition.messaging_method,
1333 FFA_PARTITION_INDIRECT_MSG);
Madhukar Pappireddy84154052022-06-21 18:30:25 -05001334 ASSERT_EQ(m.vm[0].partition.ns_interrupts_action, NS_ACTION_ME);
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001335 ASSERT_EQ(m.vm[0].partition.mem_regions[0].base_address, 0x7100000);
1336 ASSERT_EQ(m.vm[0].partition.mem_regions[0].page_count, 4);
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -07001337 ASSERT_EQ(m.vm[0].partition.mem_regions[0].attributes, 3);
Olivier Deprez035fa152022-03-14 11:19:10 +01001338 ASSERT_EQ(m.vm[0].partition.mem_regions[1].attributes, (8 | 3));
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001339 ASSERT_EQ(m.vm[0].partition.rxtx.available, true);
1340 ASSERT_EQ(m.vm[0].partition.rxtx.rx_buffer->base_address, 0x7300000);
1341 ASSERT_EQ(m.vm[0].partition.rxtx.rx_buffer->page_count, 1);
1342 ASSERT_EQ(m.vm[0].partition.rxtx.rx_buffer->attributes, 1);
Daniel Boulby9279b552022-06-28 17:04:01 +01001343 ASSERT_EQ(m.vm[0].partition.rxtx.tx_buffer->base_address, 0x7301000);
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001344 ASSERT_EQ(m.vm[0].partition.rxtx.tx_buffer->page_count, 1);
1345 ASSERT_EQ(m.vm[0].partition.rxtx.tx_buffer->attributes, 3);
Olivier Deprez035fa152022-03-14 11:19:10 +01001346 ASSERT_EQ(m.vm[0].partition.dev_regions[0].base_address, 0x7400000);
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001347 ASSERT_EQ(m.vm[0].partition.dev_regions[0].page_count, 16);
1348
Olivier Deprez035fa152022-03-14 11:19:10 +01001349 ASSERT_EQ(m.vm[0].partition.dev_regions[0].attributes, 3);
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001350 ASSERT_EQ(m.vm[0].partition.dev_regions[0].smmu_id, 1);
1351 ASSERT_EQ(m.vm[0].partition.dev_regions[0].stream_ids[0], 0);
1352 ASSERT_EQ(m.vm[0].partition.dev_regions[0].stream_ids[1], 1);
1353 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[0].id, 2);
1354 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[0].attributes, 3);
1355 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[1].id, 4);
1356 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[1].attributes, 5);
Olivier Deprez035fa152022-03-14 11:19:10 +01001357 ASSERT_EQ(m.vm[0].partition.dev_regions[1].attributes, (8 | 1));
Olivier Deprez62d99e32020-01-09 15:58:07 +01001358}
1359
David Brazdil7a462ec2019-08-15 12:27:47 +01001360} /* namespace */