blob: 6c66d791a68b6a815eaf47f1b2d134864a2ab394 [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" {
17#include "hf/manifest.h"
18}
19
20namespace
21{
Andrew Scullae9962e2019-10-03 16:51:16 +010022using ::testing::ElementsAre;
David Brazdil7a462ec2019-08-15 12:27:47 +010023using ::testing::Eq;
Andrew Scullae9962e2019-10-03 16:51:16 +010024using ::testing::IsEmpty;
David Brazdil7a462ec2019-08-15 12:27:47 +010025using ::testing::NotNull;
26
David Brazdil52256ff2019-08-23 15:15:15 +010027template <typename T>
David Brazdil0dbb41f2019-09-09 18:03:35 +010028void exec(const char *program, const char *args[], const T &stdin,
David Brazdil52256ff2019-08-23 15:15:15 +010029 std::vector<char> *stdout)
30{
31 /* Create two pipes, one for stdin and one for stdout. */
32 int pipes[2][2];
33 pipe(pipes[0]);
34 pipe(pipes[1]);
David Brazdil7a462ec2019-08-15 12:27:47 +010035
David Brazdil52256ff2019-08-23 15:15:15 +010036 /* Assign FDs for reading/writing by the parent/child. */
37 int parent_read_fd = pipes[1][0]; /* stdout pipe, read FD */
38 int parent_write_fd = pipes[0][1]; /* stdin pipe, write FD */
39 int child_read_fd = pipes[0][0]; /* stdin pipe, read FD */
40 int child_write_fd = pipes[1][1]; /* stdout pipe, write FD */
David Brazdil7a462ec2019-08-15 12:27:47 +010041
David Brazdil52256ff2019-08-23 15:15:15 +010042 if (fork()) {
43 /* Parent process. */
44 std::array<char, 128> buf;
45 ssize_t res;
46
47 /* Close child FDs which won't be used. */
48 close(child_read_fd);
49 close(child_write_fd);
50
51 /* Write to stdin. */
52 for (size_t count = 0; count < stdin.size();) {
53 res = write(parent_write_fd, stdin.data() + count,
54 stdin.size() - count);
55 if (res < 0) {
56 std::cerr << "IO error" << std::endl;
57 exit(1);
58 }
59 count += res;
60 }
61 close(parent_write_fd);
62
63 /* Read from stdout. */
64 while (true) {
65 res = read(parent_read_fd, buf.data(), buf.size());
66 if (res == 0) {
67 /* EOF */
68 break;
69 } else if (res < 0) {
70 std::cerr << "IO error" << std::endl;
71 exit(1);
72 }
73 stdout->insert(stdout->end(), buf.begin(),
74 buf.begin() + res);
75 }
76 close(parent_read_fd);
77 } else {
78 /* Child process. */
79
80 /* Redirect stdin/stdout to read/write FDs. */
81 dup2(child_read_fd, STDIN_FILENO);
82 dup2(child_write_fd, STDOUT_FILENO);
83
84 /* Close all FDs which are now unused. */
85 close(child_read_fd);
86 close(child_write_fd);
87 close(parent_read_fd);
88 close(parent_write_fd);
89
90 /* Execute the given program. */
David Brazdil0dbb41f2019-09-09 18:03:35 +010091 execv(program, const_cast<char *const *>(args));
David Brazdil52256ff2019-08-23 15:15:15 +010092 }
93}
94
95/**
96 * Class for programatically building a Device Tree.
97 *
98 * Usage:
99 * std::vector<char> dtb = ManifestDtBuilder()
100 * .Command1()
101 * .Command2()
102 * ...
103 * .CommandN()
104 * .Build();
105 */
106class ManifestDtBuilder
107{
108 public:
109 ManifestDtBuilder()
110 {
111 dts_ << "/dts-v1/;" << std::endl;
112 dts_ << std::endl;
113
114 /* Start root node. */
115 StartChild("/");
116 }
117
Andrew Scullae9962e2019-10-03 16:51:16 +0100118 std::vector<char> Build(bool dump = false)
David Brazdil52256ff2019-08-23 15:15:15 +0100119 {
David Brazdil0dbb41f2019-09-09 18:03:35 +0100120 const char *program = "./build/image/dtc.py";
121 const char *dtc_args[] = {program, "compile", NULL};
David Brazdil52256ff2019-08-23 15:15:15 +0100122 std::vector<char> dtc_stdout;
123
124 /* Finish root node. */
125 EndChild();
126
Andrew Scullae9962e2019-10-03 16:51:16 +0100127 if (dump) {
128 Dump();
129 }
130
David Brazdil0dbb41f2019-09-09 18:03:35 +0100131 exec(program, dtc_args, dts_.str(), &dtc_stdout);
David Brazdil52256ff2019-08-23 15:15:15 +0100132 return dtc_stdout;
133 }
134
Andrew Scullae9962e2019-10-03 16:51:16 +0100135 void Dump()
136 {
137 std::cerr << dts_.str() << std::endl;
138 }
139
David Brazdil52256ff2019-08-23 15:15:15 +0100140 ManifestDtBuilder &StartChild(const std::string_view &name)
141 {
142 dts_ << name << " {" << std::endl;
143 return *this;
144 }
145
146 ManifestDtBuilder &EndChild()
147 {
148 dts_ << "};" << std::endl;
149 return *this;
150 }
151
David Brazdil74e9c3b2019-08-28 11:09:08 +0100152 ManifestDtBuilder &Compatible(const std::vector<std::string_view>
153 &value = {"hafnium,hafnium"})
154 {
155 return StringListProperty("compatible", value);
156 }
157
David Brazdil52256ff2019-08-23 15:15:15 +0100158 ManifestDtBuilder &DebugName(const std::string_view &value)
159 {
160 return StringProperty("debug_name", value);
161 }
162
Manish Pandey6542f5c2020-04-27 14:37:46 +0100163 ManifestDtBuilder &Description(const std::string_view &value)
164 {
165 return StringProperty("description", value);
166 }
167
David Brazdil52256ff2019-08-23 15:15:15 +0100168 ManifestDtBuilder &KernelFilename(const std::string_view &value)
169 {
170 return StringProperty("kernel_filename", value);
171 }
172
David Brazdile6f83222019-09-23 14:47:37 +0100173 ManifestDtBuilder &RamdiskFilename(const std::string_view &value)
174 {
175 return StringProperty("ramdisk_filename", value);
176 }
177
David Brazdil080ee312020-02-25 15:30:30 -0800178 ManifestDtBuilder &BootAddress(uint64_t value)
179 {
180 return Integer64Property("boot_address", value);
181 }
182
Andrew Scullae9962e2019-10-03 16:51:16 +0100183 ManifestDtBuilder &VcpuCount(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100184 {
185 return IntegerProperty("vcpu_count", value);
186 }
187
Andrew Scullae9962e2019-10-03 16:51:16 +0100188 ManifestDtBuilder &MemSize(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100189 {
190 return IntegerProperty("mem_size", value);
191 }
192
Andrew Scullae9962e2019-10-03 16:51:16 +0100193 ManifestDtBuilder &SmcWhitelist(const std::vector<uint32_t> &value)
194 {
195 return IntegerListProperty("smc_whitelist", value);
196 }
197
198 ManifestDtBuilder &SmcWhitelistPermissive()
199 {
200 return BooleanProperty("smc_whitelist_permissive");
201 }
202
Olivier Deprez62d99e32020-01-09 15:58:07 +0100203 ManifestDtBuilder &LoadAddress(uint64_t value)
204 {
205 return Integer64Property("load_address", value);
206 }
207
208 ManifestDtBuilder &FfaPartition()
209 {
210 return BooleanProperty("is_ffa_partition");
211 }
212
Andrew Scullae9962e2019-10-03 16:51:16 +0100213 ManifestDtBuilder &Property(const std::string_view &name,
214 const std::string_view &value)
215 {
216 dts_ << name << " = " << value << ";" << std::endl;
217 return *this;
218 }
219
Manish Pandeyfa1f2912020-05-05 12:57:01 +0100220 ManifestDtBuilder &Label(const std::string_view &name)
221 {
222 dts_ << name << ": ";
223 return *this;
224 }
225
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100226 ManifestDtBuilder &FfaValidManifest()
227 {
228 Compatible({"arm,ffa-manifest-1.0"});
229 Property("ffa-version", "<0x10000>");
230 Property("uuid",
231 "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>");
232 Property("execution-ctx-count", "<1>");
233 Property("exception-level", "<2>");
234 Property("execution-state", "<0>");
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100235 Property("entrypoint-offset", "<0x00001000>");
236 Property("xlat-granule", "<0>");
J-Alvesb37fd082020-10-22 12:29:21 +0100237 Property("boot-order", "<0>");
Maksims Svecovsb596eab2021-04-27 00:52:27 +0100238 Property("messaging-method", "<4>");
Maksims Svecovs9ddf86a2021-05-06 17:17:21 +0100239 BooleanProperty("managed-exit");
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100240 return *this;
241 }
242
David Brazdil52256ff2019-08-23 15:15:15 +0100243 private:
244 ManifestDtBuilder &StringProperty(const std::string_view &name,
245 const std::string_view &value)
246 {
247 dts_ << name << " = \"" << value << "\";" << std::endl;
248 return *this;
249 }
250
David Brazdil74e9c3b2019-08-28 11:09:08 +0100251 ManifestDtBuilder &StringListProperty(
252 const std::string_view &name,
253 const std::vector<std::string_view> &value)
254 {
255 bool is_first = true;
256
257 dts_ << name << " = ";
258 for (const std::string_view &entry : value) {
259 if (is_first) {
260 is_first = false;
261 } else {
262 dts_ << ", ";
263 }
264 dts_ << "\"" << entry << "\"";
265 }
266 dts_ << ";" << std::endl;
267 return *this;
268 }
269
David Brazdil52256ff2019-08-23 15:15:15 +0100270 ManifestDtBuilder &IntegerProperty(const std::string_view &name,
Andrew Scullae9962e2019-10-03 16:51:16 +0100271 uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100272 {
273 dts_ << name << " = <" << value << ">;" << std::endl;
274 return *this;
275 }
276
David Brazdil080ee312020-02-25 15:30:30 -0800277 ManifestDtBuilder &Integer64Property(const std::string_view &name,
278 uint64_t value)
279 {
280 uint32_t high = value >> 32;
281 uint32_t low = (uint32_t)value;
282 dts_ << name << " = <" << high << " " << low << ">;"
283 << std::endl;
284 return *this;
285 }
286
Andrew Scullae9962e2019-10-03 16:51:16 +0100287 ManifestDtBuilder &IntegerListProperty(
288 const std::string_view &name,
289 const std::vector<uint32_t> &value)
290 {
291 dts_ << name << " = < ";
292 for (const uint32_t entry : value) {
293 dts_ << entry << " ";
294 }
295 dts_ << ">;" << std::endl;
296 return *this;
297 }
298
299 ManifestDtBuilder &BooleanProperty(const std::string_view &name)
300 {
Andrew Scull5dc089e2019-11-04 13:21:03 +0000301 dts_ << name << ";" << std::endl;
302 return *this;
Andrew Scullae9962e2019-10-03 16:51:16 +0100303 }
304
David Brazdil52256ff2019-08-23 15:15:15 +0100305 std::stringstream dts_;
306};
307
David Brazdila2358d42020-01-27 18:51:38 +0000308static enum manifest_return_code manifest_from_vec(struct manifest *m,
309 const std::vector<char> &vec)
David Brazdil0dbb41f2019-09-09 18:03:35 +0100310{
David Brazdila2358d42020-01-27 18:51:38 +0000311 struct memiter it;
Olivier Deprez62d99e32020-01-09 15:58:07 +0100312 struct mpool ppool;
313 struct mm_stage1_locked mm_stage1_locked;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100314
David Brazdila2358d42020-01-27 18:51:38 +0000315 memiter_init(&it, vec.data(), vec.size());
Olivier Deprez62d99e32020-01-09 15:58:07 +0100316 return manifest_init(mm_stage1_locked, m, &it, &ppool);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100317}
318
David Brazdil52256ff2019-08-23 15:15:15 +0100319TEST(manifest, no_hypervisor_node)
David Brazdil7a462ec2019-08-15 12:27:47 +0100320{
321 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100322 std::vector<char> dtb = ManifestDtBuilder().Build();
David Brazdil7a462ec2019-08-15 12:27:47 +0100323
David Brazdila2358d42020-01-27 18:51:38 +0000324 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil7a462ec2019-08-15 12:27:47 +0100325 MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
326}
327
David Brazdil74e9c3b2019-08-28 11:09:08 +0100328TEST(manifest, no_compatible_property)
David Brazdil7a462ec2019-08-15 12:27:47 +0100329{
330 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100331
David Brazdil52256ff2019-08-23 15:15:15 +0100332 /* clang-format off */
333 std::vector<char> dtb = ManifestDtBuilder()
334 .StartChild("hypervisor")
335 .EndChild()
336 .Build();
337 /* clang-format on */
338
David Brazdilf4925382020-03-25 13:33:51 +0000339 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil7a462ec2019-08-15 12:27:47 +0100340}
341
David Brazdil74e9c3b2019-08-28 11:09:08 +0100342TEST(manifest, not_compatible)
David Brazdil7a462ec2019-08-15 12:27:47 +0100343{
344 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100345
David Brazdil52256ff2019-08-23 15:15:15 +0100346 /* clang-format off */
347 std::vector<char> dtb = ManifestDtBuilder()
348 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100349 .Compatible({ "foo,bar" })
350 .EndChild()
351 .Build();
352 /* clang-format on */
353
David Brazdila2358d42020-01-27 18:51:38 +0000354 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100355}
356
357TEST(manifest, compatible_one_of_many)
358{
359 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100360
361 /* clang-format off */
362 std::vector<char> dtb = ManifestDtBuilder()
363 .StartChild("hypervisor")
364 .Compatible({ "foo,bar", "hafnium,hafnium" })
365 .StartChild("vm1")
366 .DebugName("primary")
367 .EndChild()
368 .EndChild()
369 .Build();
370 /* clang-format on */
371
David Brazdila2358d42020-01-27 18:51:38 +0000372 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100373}
374
375TEST(manifest, no_vm_nodes)
376{
377 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100378
379 /* clang-format off */
380 std::vector<char> dtb = ManifestDtBuilder()
381 .StartChild("hypervisor")
382 .Compatible()
383 .EndChild()
384 .Build();
385 /* clang-format on */
386
David Brazdila2358d42020-01-27 18:51:38 +0000387 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NO_PRIMARY_VM);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100388}
389
390static std::vector<char> gen_long_string_dtb(bool valid)
391{
392 const char last_valid[] = "1234567890123456789012345678901";
393 const char first_invalid[] = "12345678901234567890123456789012";
David Brazdil136f2942019-09-23 14:11:03 +0100394 static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
395 static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100396
397 /* clang-format off */
398 return ManifestDtBuilder()
399 .StartChild("hypervisor")
400 .Compatible()
401 .StartChild("vm1")
402 .DebugName(valid ? last_valid : first_invalid)
403 .EndChild()
404 .EndChild()
405 .Build();
406 /* clang-format on */
407}
408
409TEST(manifest, long_string)
410{
411 struct manifest m;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100412 std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
413 std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
414
David Brazdila2358d42020-01-27 18:51:38 +0000415 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
416 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
417 MANIFEST_ERROR_STRING_TOO_LONG);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100418}
419
420TEST(manifest, reserved_vm_id)
421{
422 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100423
424 /* clang-format off */
425 std::vector<char> dtb = ManifestDtBuilder()
426 .StartChild("hypervisor")
427 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100428 .StartChild("vm1")
429 .DebugName("primary_vm")
430 .EndChild()
431 .StartChild("vm0")
432 .DebugName("reserved_vm")
433 .VcpuCount(1)
434 .MemSize(0x1000)
435 .KernelFilename("kernel")
436 .EndChild()
437 .EndChild()
438 .Build();
439 /* clang-format on */
440
David Brazdila2358d42020-01-27 18:51:38 +0000441 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_RESERVED_VM_ID);
David Brazdil7a462ec2019-08-15 12:27:47 +0100442}
443
Andrew Scullae9962e2019-10-03 16:51:16 +0100444static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
David Brazdil52256ff2019-08-23 15:15:15 +0100445{
446 /* clang-format off */
447 return ManifestDtBuilder()
448 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100449 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100450 .StartChild("vm1")
451 .DebugName("primary_vm")
452 .EndChild()
453 .StartChild("vm2")
454 .DebugName("secondary_vm")
455 .VcpuCount(vcpu_count)
456 .MemSize(0x1000)
457 .KernelFilename("kernel")
458 .EndChild()
459 .EndChild()
460 .Build();
461 /* clang-format on */
462}
David Brazdil7a462ec2019-08-15 12:27:47 +0100463
464TEST(manifest, vcpu_count_limit)
465{
466 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100467 std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
468 std::vector<char> dtb_first_invalid =
469 gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
David Brazdil7a462ec2019-08-15 12:27:47 +0100470
David Brazdila2358d42020-01-27 18:51:38 +0000471 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100472 ASSERT_EQ(m.vm_count, 2);
David Brazdil7a462ec2019-08-15 12:27:47 +0100473 ASSERT_EQ(m.vm[1].secondary.vcpu_count, UINT16_MAX);
474
David Brazdila2358d42020-01-27 18:51:38 +0000475 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100476 MANIFEST_ERROR_INTEGER_OVERFLOW);
David Brazdil7a462ec2019-08-15 12:27:47 +0100477}
478
David Brazdile6f83222019-09-23 14:47:37 +0100479TEST(manifest, no_ramdisk_primary)
480{
481 struct manifest m;
David Brazdile6f83222019-09-23 14:47:37 +0100482
483 /* clang-format off */
484 std::vector<char> dtb = ManifestDtBuilder()
485 .StartChild("hypervisor")
486 .Compatible()
487 .StartChild("vm1")
488 .DebugName("primary_vm")
489 .EndChild()
490 .EndChild()
491 .Build();
492 /* clang-format on */
493
David Brazdila2358d42020-01-27 18:51:38 +0000494 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdile6f83222019-09-23 14:47:37 +0100495 ASSERT_EQ(m.vm_count, 1);
496 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
497 ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
498}
499
David Brazdil080ee312020-02-25 15:30:30 -0800500TEST(manifest, no_boot_address_primary)
501{
502 struct manifest m;
503
504 /* clang-format off */
505 std::vector<char> dtb = ManifestDtBuilder()
506 .StartChild("hypervisor")
507 .Compatible()
508 .StartChild("vm1")
509 .DebugName("primary_vm")
510 .EndChild()
511 .EndChild()
512 .Build();
513 /* clang-format on */
514
515 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
516 ASSERT_EQ(m.vm_count, 1);
517 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
518 ASSERT_EQ(m.vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
519}
520
521TEST(manifest, boot_address_primary)
522{
523 struct manifest m;
524 const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
525
526 /* clang-format off */
527 std::vector<char> dtb = ManifestDtBuilder()
528 .StartChild("hypervisor")
529 .Compatible()
530 .StartChild("vm1")
531 .DebugName("primary_vm")
532 .BootAddress(addr)
533 .EndChild()
534 .EndChild()
535 .Build();
536 /* clang-format on */
537
538 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
539 ASSERT_EQ(m.vm_count, 1);
540 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
541 ASSERT_EQ(m.vm[0].primary.boot_address, addr);
542}
543
Andrew Scullb2c3a242019-11-04 13:52:36 +0000544static std::vector<char> gen_malformed_boolean_dtb(
545 const std::string_view &value)
Andrew Scullae9962e2019-10-03 16:51:16 +0100546{
Andrew Scullae9962e2019-10-03 16:51:16 +0100547 /* clang-format off */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000548 return ManifestDtBuilder()
Andrew Scullae9962e2019-10-03 16:51:16 +0100549 .StartChild("hypervisor")
550 .Compatible()
551 .StartChild("vm1")
552 .DebugName("primary_vm")
Andrew Scullb2c3a242019-11-04 13:52:36 +0000553 .Property("smc_whitelist_permissive", value)
Andrew Scull5dc089e2019-11-04 13:21:03 +0000554 .EndChild()
Andrew Scullae9962e2019-10-03 16:51:16 +0100555 .EndChild()
556 .Build();
557 /* clang-format on */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000558}
Andrew Scullae9962e2019-10-03 16:51:16 +0100559
Andrew Scullb2c3a242019-11-04 13:52:36 +0000560TEST(manifest, malformed_booleans)
561{
562 struct manifest m;
Andrew Scullae9962e2019-10-03 16:51:16 +0100563
Andrew Scullb2c3a242019-11-04 13:52:36 +0000564 std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
565 std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
566 std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
567 std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
Andrew Scullae9962e2019-10-03 16:51:16 +0100568
David Brazdila2358d42020-01-27 18:51:38 +0000569 ASSERT_EQ(manifest_from_vec(&m, dtb_false),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000570 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000571 ASSERT_EQ(manifest_from_vec(&m, dtb_true),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000572 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000573 ASSERT_EQ(manifest_from_vec(&m, dtb_0),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000574 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000575 ASSERT_EQ(manifest_from_vec(&m, dtb_1),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000576 MANIFEST_ERROR_MALFORMED_BOOLEAN);
Andrew Scullae9962e2019-10-03 16:51:16 +0100577}
578
David Brazdil7a462ec2019-08-15 12:27:47 +0100579TEST(manifest, valid)
580{
581 struct manifest m;
582 struct manifest_vm *vm;
David Brazdil7a462ec2019-08-15 12:27:47 +0100583
David Brazdil52256ff2019-08-23 15:15:15 +0100584 /* clang-format off */
585 std::vector<char> dtb = ManifestDtBuilder()
586 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100587 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100588 .StartChild("vm1")
589 .DebugName("primary_vm")
Andrew Scull72b43c02019-09-18 13:53:45 +0100590 .KernelFilename("primary_kernel")
David Brazdile6f83222019-09-23 14:47:37 +0100591 .RamdiskFilename("primary_ramdisk")
Andrew Scullae9962e2019-10-03 16:51:16 +0100592 .SmcWhitelist({0x32000000, 0x33001111})
David Brazdil52256ff2019-08-23 15:15:15 +0100593 .EndChild()
594 .StartChild("vm3")
595 .DebugName("second_secondary_vm")
596 .VcpuCount(43)
597 .MemSize(0x12345)
Andrew Scull72b43c02019-09-18 13:53:45 +0100598 .KernelFilename("second_secondary_kernel")
David Brazdil52256ff2019-08-23 15:15:15 +0100599 .EndChild()
600 .StartChild("vm2")
601 .DebugName("first_secondary_vm")
602 .VcpuCount(42)
603 .MemSize(12345)
Andrew Scullae9962e2019-10-03 16:51:16 +0100604 .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
605 .SmcWhitelistPermissive()
David Brazdil52256ff2019-08-23 15:15:15 +0100606 .EndChild()
607 .EndChild()
608 .Build();
609 /* clang-format on */
610
David Brazdila2358d42020-01-27 18:51:38 +0000611 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100612 ASSERT_EQ(m.vm_count, 3);
David Brazdil7a462ec2019-08-15 12:27:47 +0100613
614 vm = &m.vm[0];
David Brazdil136f2942019-09-23 14:11:03 +0100615 ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
616 ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
David Brazdile6f83222019-09-23 14:47:37 +0100617 ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
618 "primary_ramdisk");
Andrew Scullae9962e2019-10-03 16:51:16 +0100619 ASSERT_THAT(
620 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
621 ElementsAre(0x32000000, 0x33001111));
622 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100623
624 vm = &m.vm[1];
David Brazdil136f2942019-09-23 14:11:03 +0100625 ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
626 ASSERT_STREQ(string_data(&vm->kernel_filename), "");
David Brazdil7a462ec2019-08-15 12:27:47 +0100627 ASSERT_EQ(vm->secondary.vcpu_count, 42);
628 ASSERT_EQ(vm->secondary.mem_size, 12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100629 ASSERT_THAT(
630 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
631 ElementsAre(0x04000000, 0x30002222, 0x31445566));
632 ASSERT_TRUE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100633
634 vm = &m.vm[2];
David Brazdil136f2942019-09-23 14:11:03 +0100635 ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
636 ASSERT_STREQ(string_data(&vm->kernel_filename),
637 "second_secondary_kernel");
David Brazdil7a462ec2019-08-15 12:27:47 +0100638 ASSERT_EQ(vm->secondary.vcpu_count, 43);
639 ASSERT_EQ(vm->secondary.mem_size, 0x12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100640 ASSERT_THAT(
641 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
642 IsEmpty());
643 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100644}
645
Olivier Deprez62d99e32020-01-09 15:58:07 +0100646/**
647 * Class for programatically building a Partition package.
648 */
649class Partition_package
650{
651 public:
652 __attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
653 char manifest_dtb[PAGE_SIZE] = {};
654
655 Partition_package(const std::vector<char> &vec)
656 {
657 // Initialise header field
658 spkg.magic = SP_PKG_HEADER_MAGIC;
659 spkg.version = SP_PKG_HEADER_VERSION;
660 spkg.pm_offset = sizeof(struct sp_pkg_header);
661 spkg.pm_size = vec.size();
662
663 // Copy dtb into package
664 std::copy(vec.begin(), vec.end(), manifest_dtb);
665 }
666};
667
668static enum manifest_return_code ffa_manifest_from_vec(
669 struct manifest *m, const std::vector<char> &vec)
670{
671 struct memiter it;
672 struct mpool ppool;
673 struct mm_stage1_locked mm_stage1_locked;
674
675 Partition_package spkg(vec);
676
677 /* clang-format off */
678 std::vector<char> core_dtb = ManifestDtBuilder()
679 .StartChild("hypervisor")
680 .Compatible()
681 .StartChild("vm1")
682 .DebugName("primary_vm")
683 .FfaPartition()
684 .LoadAddress((uint64_t)&spkg)
685 .EndChild()
686 .EndChild()
687 .Build();
688 /* clang-format on */
Olivier Deprez62d99e32020-01-09 15:58:07 +0100689 memiter_init(&it, core_dtb.data(), core_dtb.size());
690 return manifest_init(mm_stage1_locked, m, &it, &ppool);
691}
692
693TEST(manifest, ffa_not_compatible)
694{
695 struct manifest m;
696
697 /* clang-format off */
698 std::vector<char> dtb = ManifestDtBuilder()
699 .Compatible({ "arm,ffa-manifest-2.0" })
700 .Property("ffa-version", "<0x10000>")
701 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
702 .Property("execution-ctx-count", "<1>")
703 .Property("exception-level", "<2>")
704 .Property("execution-state", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100705 .Property("entrypoint-offset", "<0x00001000>")
706 .Property("xlat-granule", "<0>")
707 .Property("messaging-method", "<1>")
708 .Build();
709 /* clang-format on */
710
711 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
712 MANIFEST_ERROR_NOT_COMPATIBLE);
713}
714
715TEST(manifest, ffa_missing_property)
716{
717 struct manifest m;
718
719 /* clang-format off */
720 std::vector<char> dtb = ManifestDtBuilder()
721 .Compatible({ "arm,ffa-manifest-1.0" })
722 .Property("ffa-version", "<0x10000>")
723 .Build();
724 /* clang-format on */
725
726 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
727 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
728}
729
730TEST(manifest, ffa_validate_sanity_check)
731{
J-Alvesb37fd082020-10-22 12:29:21 +0100732 /*
733 * TODO: write test excluding all optional fields of the manifest, in
734 * accordance with specification.
735 */
Olivier Deprez62d99e32020-01-09 15:58:07 +0100736 struct manifest m;
737
738 /* Incompatible version */
739 /* clang-format off */
740 std::vector<char> dtb = ManifestDtBuilder()
741 .Compatible({ "arm,ffa-manifest-1.0" })
742 .Property("ffa-version", "<0xa1>")
743 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
744 .Property("execution-ctx-count", "<1>")
745 .Property("exception-level", "<2>")
746 .Property("execution-state", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100747 .Property("entrypoint-offset", "<0x00001000>")
748 .Property("xlat-granule", "<0>")
J-Alvesb37fd082020-10-22 12:29:21 +0100749 .Property("boot-order", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100750 .Property("messaging-method", "<1>")
751 .Build();
752 /* clang-format on */
753 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
754 MANIFEST_ERROR_NOT_COMPATIBLE);
755
756 /* Incompatible translation granule */
757 /* clang-format off */
758 dtb = ManifestDtBuilder()
759 .Compatible({ "arm,ffa-manifest-1.0" })
760 .Property("ffa-version", "<0x10000>")
761 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
762 .Property("execution-ctx-count", "<1>")
763 .Property("exception-level", "<2>")
764 .Property("execution-state", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100765 .Property("entrypoint-offset", "<0x00001000>")
766 .Property("xlat-granule", "<3>")
J-Alvesb37fd082020-10-22 12:29:21 +0100767 .Property("boot-order", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100768 .Property("messaging-method", "<1>")
769 .Build();
770 /* clang-format on */
771 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
772 MANIFEST_ERROR_NOT_COMPATIBLE);
773
774 /* Incompatible exeption level */
775 /* clang-format off */
776 dtb = ManifestDtBuilder()
777 .Compatible({ "arm,ffa-manifest-1.0" })
778 .Property("ffa-version", "<0x10000>")
779 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
780 .Property("execution-ctx-count", "<1>")
781 .Property("exception-level", "<6>")
782 .Property("execution-state", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100783 .Property("entrypoint-offset", "<0x00001000>")
784 .Property("xlat-granule", "<0>")
J-Alvesb37fd082020-10-22 12:29:21 +0100785 .Property("boot-order", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100786 .Property("messaging-method", "<1>")
787 .Build();
788 /* clang-format on */
789 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
790 MANIFEST_ERROR_NOT_COMPATIBLE);
791
792 /* Incompatible execution state */
793 /* clang-format off */
794 dtb = ManifestDtBuilder()
795 .Compatible({ "arm,ffa-manifest-1.0" })
796 .Property("ffa-version", "<0x10000>")
797 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
798 .Property("execution-ctx-count", "<1>")
799 .Property("exception-level", "<2>")
800 .Property("execution-state", "<2>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100801 .Property("entrypoint-offset", "<0x00001000>")
802 .Property("xlat-granule", "<0>")
J-Alvesb37fd082020-10-22 12:29:21 +0100803 .Property("boot-order", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100804 .Property("messaging-method", "<1>")
805 .Build();
806 /* clang-format on */
807 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
808 MANIFEST_ERROR_NOT_COMPATIBLE);
809
810 /* Incompatible messaging method */
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", "<2>")
818 .Property("execution-state", "<0>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100819 .Property("entrypoint-offset", "<0x00001000>")
820 .Property("xlat-granule", "<0>")
J-Alvesb37fd082020-10-22 12:29:21 +0100821 .Property("boot-order", "<0>")
Maksims Svecovsb596eab2021-04-27 00:52:27 +0100822 .Property("messaging-method", "<16>")
Olivier Deprez62d99e32020-01-09 15:58:07 +0100823 .Build();
824 /* clang-format on */
825 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
826 MANIFEST_ERROR_NOT_COMPATIBLE);
827}
828
Manish Pandeyfa1f2912020-05-05 12:57:01 +0100829TEST(manifest, ffa_validate_rxtx_info)
830{
831 struct manifest m;
832
833 /* Not Compatible */
834 /* clang-format off */
835 std::vector<char> dtb = ManifestDtBuilder()
836 .FfaValidManifest()
837 .StartChild("rx_tx-info")
838 .Compatible({ "foo,bar" })
839 .EndChild()
840 .Build();
841 /* clang-format on */
842 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
843 MANIFEST_ERROR_NOT_COMPATIBLE);
844
845 /* Missing Properties */
846 /* clang-format off */
847 dtb = ManifestDtBuilder()
848 .FfaValidManifest()
849 .StartChild("rx_tx-info")
850 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
851 .EndChild()
852 .Build();
853 /* clang-format on */
854 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
855 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
856}
857
Manish Pandey6542f5c2020-04-27 14:37:46 +0100858TEST(manifest, ffa_validate_mem_regions)
859{
860 struct manifest m;
861
862 /* Not Compatible */
863 /* clang-format off */
864 std::vector<char> dtb = ManifestDtBuilder()
865 .FfaValidManifest()
866 .StartChild("memory-regions")
867 .Compatible({ "foo,bar" })
868 .EndChild()
869 .Build();
870 /* clang-format on */
871 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
872 MANIFEST_ERROR_NOT_COMPATIBLE);
873
874 /* Memory regions unavailable */
875 /* clang-format off */
876 dtb = ManifestDtBuilder()
877 .FfaValidManifest()
878 .StartChild("memory-regions")
879 .Compatible({ "arm,ffa-manifest-memory-regions" })
880 .EndChild()
881 .Build();
882 /* clang-format on */
883 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
884 MANIFEST_ERROR_MEMORY_REGION_NODE_EMPTY);
885
886 /* Missing Properties */
887 /* clang-format off */
888 dtb = ManifestDtBuilder()
889 .FfaValidManifest()
890 .StartChild("memory-regions")
891 .Compatible({ "arm,ffa-manifest-memory-regions" })
892 .StartChild("test-memory")
893 .Description("test-memory")
894 .EndChild()
895 .EndChild()
896 .Build();
897 /* clang-format on */
898 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
899 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
Manish Pandeyf06c9072020-09-29 15:41:58 +0100900
901 /* Different RXTX buffer sizes */
902 /* clang-format off */
903 dtb = ManifestDtBuilder()
904 .FfaValidManifest()
905 .StartChild("memory-regions")
906 .Compatible({ "arm,ffa-manifest-memory-regions" })
907 .Label("rx")
908 .StartChild("rx")
909 .Description("rx-buffer")
910 .Property("base-address", "<0x7300000>")
911 .Property("pages-count", "<1>")
912 .Property("attributes", "<1>")
913 .EndChild()
914 .Label("tx")
915 .StartChild("tx")
916 .Description("tx-buffer")
917 .Property("base-address", "<0x7310000>")
918 .Property("pages-count", "<2>")
919 .Property("attributes", "<3>")
920 .EndChild()
921 .EndChild()
922 .StartChild("rx_tx-info")
923 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
924 .Property("rx-buffer", "<&rx>")
925 .Property("tx-buffer", "<&tx>")
926 .EndChild()
927 .Build();
928 /* clang-format on */
929 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
930 MANIFEST_ERROR_RXTX_SIZE_MISMATCH);
Manish Pandey6542f5c2020-04-27 14:37:46 +0100931}
932
Manish Pandeye68e7932020-04-23 15:29:28 +0100933TEST(manifest, ffa_validate_dev_regions)
934{
935 struct manifest m;
936
937 /* Not Compatible */
938 /* clang-format off */
939 std::vector<char> dtb = ManifestDtBuilder()
940 .FfaValidManifest()
941 .StartChild("device-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
949 /* Memory regions unavailable */
950 /* clang-format off */
951 dtb = ManifestDtBuilder()
952 .FfaValidManifest()
953 .StartChild("device-regions")
954 .Compatible({ "arm,ffa-manifest-device-regions" })
955 .EndChild()
956 .Build();
957 /* clang-format on */
958 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
959 MANIFEST_ERROR_DEVICE_REGION_NODE_EMPTY);
960
961 /* Missing Properties */
962 /* clang-format off */
963 dtb = ManifestDtBuilder()
964 .FfaValidManifest()
965 .StartChild("device-regions")
966 .Compatible({ "arm,ffa-manifest-device-regions" })
967 .StartChild("test-device")
968 .Description("test-device")
969 .EndChild()
970 .EndChild()
971 .Build();
972 /* clang-format on */
973 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
974 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
975
976 /* Malformed interrupt list pair */
977 /* clang-format off */
978 dtb = ManifestDtBuilder()
979 .FfaValidManifest()
980 .StartChild("device-regions")
981 .Compatible({ "arm,ffa-manifest-device-regions" })
982 .StartChild("test-device")
983 .Description("test-device")
984 .Property("base-address", "<0x7200000>")
985 .Property("pages-count", "<16>")
986 .Property("attributes", "<3>")
987 .Property("smmu-id", "<1>")
988 .Property("stream-ids", "<0 1>")
989 .Property("interrupts", "<2 3>, <4>")
990 .EndChild()
991 .EndChild()
992 .Build();
993 /* clang-format on */
994 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
995 MANIFEST_ERROR_MALFORMED_INTEGER_LIST);
996}
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -0700997TEST(manifest, ffa_invalid_memory_region_attributes)
998{
999 struct manifest m;
1000
1001 /* clang-format off */
1002 std::vector<char> dtb = ManifestDtBuilder()
1003 .FfaValidManifest()
1004 .StartChild("rx_tx-info")
1005 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1006 .Property("rx-buffer", "<&rx>")
1007 .Property("tx-buffer", "<&tx>")
1008 .EndChild()
1009 .StartChild("memory-regions")
1010 .Compatible({ "arm,ffa-manifest-memory-regions" })
1011 .StartChild("test-memory")
1012 .Description("test-memory")
1013 .Property("base-address", "<0x7100000>")
1014 .Property("pages-count", "<4>")
1015 .Property("attributes", "<7>")
1016 .EndChild()
1017 .Label("rx")
1018 .StartChild("rx")
1019 .Description("rx-buffer")
1020 .Property("base-address", "<0x7300000>")
1021 .Property("pages-count", "<1>")
1022 .Property("attributes", "<1>")
1023 .EndChild()
1024 .Label("tx")
1025 .StartChild("tx")
1026 .Description("tx-buffer")
1027 .Property("base-address", "<0x7310000>")
1028 .Property("pages-count", "<1>")
1029 .Property("attributes", "<3>")
1030 .EndChild()
1031 .EndChild()
1032 .Build();
1033 /* clang-format on */
1034
1035 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1036 MANIFEST_ERROR_INVALID_MEM_PERM);
1037}
1038
1039TEST(manifest, ffa_invalid_device_region_attributes)
1040{
1041 struct manifest m;
1042
1043 /* clang-format off */
1044 std::vector<char> dtb = ManifestDtBuilder()
1045 .FfaValidManifest()
1046 .StartChild("rx_tx-info")
1047 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1048 .Property("rx-buffer", "<&rx>")
1049 .Property("tx-buffer", "<&tx>")
1050 .EndChild()
1051 .StartChild("memory-regions")
1052 .Compatible({ "arm,ffa-manifest-memory-regions" })
1053 .StartChild("test-memory")
1054 .Description("test-memory")
1055 .Property("base-address", "<0x7100000>")
1056 .Property("pages-count", "<4>")
1057 .Property("attributes", "<3>")
1058 .EndChild()
1059 .Label("rx")
1060 .StartChild("rx")
1061 .Description("rx-buffer")
1062 .Property("base-address", "<0x7300000>")
1063 .Property("pages-count", "<1>")
1064 .Property("attributes", "<1>")
1065 .EndChild()
1066 .Label("tx")
1067 .StartChild("tx")
1068 .Description("tx-buffer")
1069 .Property("base-address", "<0x7310000>")
1070 .Property("pages-count", "<1>")
1071 .Property("attributes", "<3>")
1072 .EndChild()
1073 .EndChild()
1074 .StartChild("device-regions")
1075 .Compatible({ "arm,ffa-manifest-device-regions" })
1076 .StartChild("test-device")
1077 .Description("test-device")
1078 .Property("base-address", "<0x7200000>")
1079 .Property("pages-count", "<16>")
1080 .Property("attributes", "<5>")
1081 .Property("smmu-id", "<1>")
1082 .Property("stream-ids", "<0 1>")
1083 .Property("interrupts", "<2 3>, <4 5>")
1084 .EndChild()
1085 .EndChild()
1086 .Build();
1087 /* clang-format on */
1088
1089 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
1090 MANIFEST_ERROR_INVALID_MEM_PERM);
1091}
Manish Pandeye68e7932020-04-23 15:29:28 +01001092
Olivier Deprez62d99e32020-01-09 15:58:07 +01001093TEST(manifest, ffa_valid)
1094{
1095 struct manifest m;
1096
1097 /* clang-format off */
1098 std::vector<char> dtb = ManifestDtBuilder()
Manish Pandeycb8fbb22020-08-18 00:04:43 +01001099 .FfaValidManifest()
Manish Pandeyfa1f2912020-05-05 12:57:01 +01001100 .StartChild("rx_tx-info")
1101 .Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
1102 .Property("rx-buffer", "<&rx>")
1103 .Property("tx-buffer", "<&tx>")
1104 .EndChild()
Manish Pandey6542f5c2020-04-27 14:37:46 +01001105 .StartChild("memory-regions")
1106 .Compatible({ "arm,ffa-manifest-memory-regions" })
1107 .StartChild("test-memory")
1108 .Description("test-memory")
1109 .Property("base-address", "<0x7100000>")
1110 .Property("pages-count", "<4>")
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -07001111 .Property("attributes", "<3>")
Manish Pandey6542f5c2020-04-27 14:37:46 +01001112 .EndChild()
Manish Pandeyfa1f2912020-05-05 12:57:01 +01001113 .Label("rx")
1114 .StartChild("rx")
1115 .Description("rx-buffer")
1116 .Property("base-address", "<0x7300000>")
1117 .Property("pages-count", "<1>")
1118 .Property("attributes", "<1>")
1119 .EndChild()
1120 .Label("tx")
1121 .StartChild("tx")
1122 .Description("tx-buffer")
1123 .Property("base-address", "<0x7310000>")
1124 .Property("pages-count", "<1>")
1125 .Property("attributes", "<3>")
1126 .EndChild()
Manish Pandey6542f5c2020-04-27 14:37:46 +01001127 .EndChild()
Manish Pandeye68e7932020-04-23 15:29:28 +01001128 .StartChild("device-regions")
1129 .Compatible({ "arm,ffa-manifest-device-regions" })
1130 .StartChild("test-device")
1131 .Description("test-device")
1132 .Property("base-address", "<0x7200000>")
1133 .Property("pages-count", "<16>")
1134 .Property("attributes", "<3>")
1135 .Property("smmu-id", "<1>")
1136 .Property("stream-ids", "<0 1>")
1137 .Property("interrupts", "<2 3>, <4 5>")
1138 .EndChild()
1139 .EndChild()
Olivier Deprez62d99e32020-01-09 15:58:07 +01001140 .Build();
1141 /* clang-format on */
1142
1143 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
1144
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001145 ASSERT_EQ(m.vm[0].partition.ffa_version, 0x10000);
Olivier Deprez62d99e32020-01-09 15:58:07 +01001146 ASSERT_THAT(
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001147 std::span(m.vm[0].partition.uuid.uuid, 4),
Olivier Deprez62d99e32020-01-09 15:58:07 +01001148 ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb));
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001149 ASSERT_EQ(m.vm[0].partition.execution_ctx_count, 1);
1150 ASSERT_EQ(m.vm[0].partition.run_time_el, S_EL1);
1151 ASSERT_EQ(m.vm[0].partition.execution_state, AARCH64);
1152 ASSERT_EQ(m.vm[0].partition.ep_offset, 0x00001000);
1153 ASSERT_EQ(m.vm[0].partition.xlat_granule, PAGE_4KB);
1154 ASSERT_EQ(m.vm[0].partition.boot_order, 0);
1155 ASSERT_EQ(m.vm[0].partition.messaging_method,
1156 FFA_PARTITION_INDIRECT_MSG);
1157 ASSERT_EQ(m.vm[0].partition.managed_exit, true);
1158 ASSERT_EQ(m.vm[0].partition.mem_regions[0].base_address, 0x7100000);
1159 ASSERT_EQ(m.vm[0].partition.mem_regions[0].page_count, 4);
Raghu Krishnamurthy384693c2021-10-11 13:56:24 -07001160 ASSERT_EQ(m.vm[0].partition.mem_regions[0].attributes, 3);
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001161 ASSERT_EQ(m.vm[0].partition.rxtx.available, true);
1162 ASSERT_EQ(m.vm[0].partition.rxtx.rx_buffer->base_address, 0x7300000);
1163 ASSERT_EQ(m.vm[0].partition.rxtx.rx_buffer->page_count, 1);
1164 ASSERT_EQ(m.vm[0].partition.rxtx.rx_buffer->attributes, 1);
1165 ASSERT_EQ(m.vm[0].partition.rxtx.tx_buffer->base_address, 0x7310000);
1166 ASSERT_EQ(m.vm[0].partition.rxtx.tx_buffer->page_count, 1);
1167 ASSERT_EQ(m.vm[0].partition.rxtx.tx_buffer->attributes, 3);
1168 ASSERT_EQ(m.vm[0].partition.dev_regions[0].base_address, 0x7200000);
1169 ASSERT_EQ(m.vm[0].partition.dev_regions[0].page_count, 16);
1170
Manish Pandeye68e7932020-04-23 15:29:28 +01001171 /* Attribute is ORed with MM_MODE_D */
Raghu Krishnamurthy8c250a92021-07-02 12:16:42 -07001172 ASSERT_EQ(m.vm[0].partition.dev_regions[0].attributes, (3 | 8));
1173 ASSERT_EQ(m.vm[0].partition.dev_regions[0].smmu_id, 1);
1174 ASSERT_EQ(m.vm[0].partition.dev_regions[0].stream_ids[0], 0);
1175 ASSERT_EQ(m.vm[0].partition.dev_regions[0].stream_ids[1], 1);
1176 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[0].id, 2);
1177 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[0].attributes, 3);
1178 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[1].id, 4);
1179 ASSERT_EQ(m.vm[0].partition.dev_regions[0].interrupts[1].attributes, 5);
Olivier Deprez62d99e32020-01-09 15:58:07 +01001180}
1181
David Brazdil7a462ec2019-08-15 12:27:47 +01001182} /* namespace */