blob: d58cb70cde0ad2460daf8c4fe07b8471380b951f [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 Pandeycb8fbb22020-08-18 00:04:43 +0100220 ManifestDtBuilder &FfaValidManifest()
221 {
222 Compatible({"arm,ffa-manifest-1.0"});
223 Property("ffa-version", "<0x10000>");
224 Property("uuid",
225 "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>");
226 Property("execution-ctx-count", "<1>");
227 Property("exception-level", "<2>");
228 Property("execution-state", "<0>");
229 Property("load-address", "<0x7000000>");
230 Property("entrypoint-offset", "<0x00001000>");
231 Property("xlat-granule", "<0>");
232 Property("messaging-method", "<1>");
233 return *this;
234 }
235
David Brazdil52256ff2019-08-23 15:15:15 +0100236 private:
237 ManifestDtBuilder &StringProperty(const std::string_view &name,
238 const std::string_view &value)
239 {
240 dts_ << name << " = \"" << value << "\";" << std::endl;
241 return *this;
242 }
243
David Brazdil74e9c3b2019-08-28 11:09:08 +0100244 ManifestDtBuilder &StringListProperty(
245 const std::string_view &name,
246 const std::vector<std::string_view> &value)
247 {
248 bool is_first = true;
249
250 dts_ << name << " = ";
251 for (const std::string_view &entry : value) {
252 if (is_first) {
253 is_first = false;
254 } else {
255 dts_ << ", ";
256 }
257 dts_ << "\"" << entry << "\"";
258 }
259 dts_ << ";" << std::endl;
260 return *this;
261 }
262
David Brazdil52256ff2019-08-23 15:15:15 +0100263 ManifestDtBuilder &IntegerProperty(const std::string_view &name,
Andrew Scullae9962e2019-10-03 16:51:16 +0100264 uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100265 {
266 dts_ << name << " = <" << value << ">;" << std::endl;
267 return *this;
268 }
269
David Brazdil080ee312020-02-25 15:30:30 -0800270 ManifestDtBuilder &Integer64Property(const std::string_view &name,
271 uint64_t value)
272 {
273 uint32_t high = value >> 32;
274 uint32_t low = (uint32_t)value;
275 dts_ << name << " = <" << high << " " << low << ">;"
276 << std::endl;
277 return *this;
278 }
279
Andrew Scullae9962e2019-10-03 16:51:16 +0100280 ManifestDtBuilder &IntegerListProperty(
281 const std::string_view &name,
282 const std::vector<uint32_t> &value)
283 {
284 dts_ << name << " = < ";
285 for (const uint32_t entry : value) {
286 dts_ << entry << " ";
287 }
288 dts_ << ">;" << std::endl;
289 return *this;
290 }
291
292 ManifestDtBuilder &BooleanProperty(const std::string_view &name)
293 {
Andrew Scull5dc089e2019-11-04 13:21:03 +0000294 dts_ << name << ";" << std::endl;
295 return *this;
Andrew Scullae9962e2019-10-03 16:51:16 +0100296 }
297
David Brazdil52256ff2019-08-23 15:15:15 +0100298 std::stringstream dts_;
299};
300
David Brazdila2358d42020-01-27 18:51:38 +0000301static enum manifest_return_code manifest_from_vec(struct manifest *m,
302 const std::vector<char> &vec)
David Brazdil0dbb41f2019-09-09 18:03:35 +0100303{
David Brazdila2358d42020-01-27 18:51:38 +0000304 struct memiter it;
Olivier Deprez62d99e32020-01-09 15:58:07 +0100305 struct mpool ppool;
306 struct mm_stage1_locked mm_stage1_locked;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100307
David Brazdila2358d42020-01-27 18:51:38 +0000308 memiter_init(&it, vec.data(), vec.size());
Olivier Deprez62d99e32020-01-09 15:58:07 +0100309 return manifest_init(mm_stage1_locked, m, &it, &ppool);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100310}
311
David Brazdil52256ff2019-08-23 15:15:15 +0100312TEST(manifest, no_hypervisor_node)
David Brazdil7a462ec2019-08-15 12:27:47 +0100313{
314 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100315 std::vector<char> dtb = ManifestDtBuilder().Build();
David Brazdil7a462ec2019-08-15 12:27:47 +0100316
David Brazdila2358d42020-01-27 18:51:38 +0000317 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil7a462ec2019-08-15 12:27:47 +0100318 MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
319}
320
David Brazdil74e9c3b2019-08-28 11:09:08 +0100321TEST(manifest, no_compatible_property)
David Brazdil7a462ec2019-08-15 12:27:47 +0100322{
323 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100324
David Brazdil52256ff2019-08-23 15:15:15 +0100325 /* clang-format off */
326 std::vector<char> dtb = ManifestDtBuilder()
327 .StartChild("hypervisor")
328 .EndChild()
329 .Build();
330 /* clang-format on */
331
David Brazdilf4925382020-03-25 13:33:51 +0000332 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil7a462ec2019-08-15 12:27:47 +0100333}
334
David Brazdil74e9c3b2019-08-28 11:09:08 +0100335TEST(manifest, not_compatible)
David Brazdil7a462ec2019-08-15 12:27:47 +0100336{
337 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100338
David Brazdil52256ff2019-08-23 15:15:15 +0100339 /* clang-format off */
340 std::vector<char> dtb = ManifestDtBuilder()
341 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100342 .Compatible({ "foo,bar" })
343 .EndChild()
344 .Build();
345 /* clang-format on */
346
David Brazdila2358d42020-01-27 18:51:38 +0000347 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100348}
349
350TEST(manifest, compatible_one_of_many)
351{
352 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100353
354 /* clang-format off */
355 std::vector<char> dtb = ManifestDtBuilder()
356 .StartChild("hypervisor")
357 .Compatible({ "foo,bar", "hafnium,hafnium" })
358 .StartChild("vm1")
359 .DebugName("primary")
360 .EndChild()
361 .EndChild()
362 .Build();
363 /* clang-format on */
364
David Brazdila2358d42020-01-27 18:51:38 +0000365 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100366}
367
368TEST(manifest, no_vm_nodes)
369{
370 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100371
372 /* clang-format off */
373 std::vector<char> dtb = ManifestDtBuilder()
374 .StartChild("hypervisor")
375 .Compatible()
376 .EndChild()
377 .Build();
378 /* clang-format on */
379
David Brazdila2358d42020-01-27 18:51:38 +0000380 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NO_PRIMARY_VM);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100381}
382
383static std::vector<char> gen_long_string_dtb(bool valid)
384{
385 const char last_valid[] = "1234567890123456789012345678901";
386 const char first_invalid[] = "12345678901234567890123456789012";
David Brazdil136f2942019-09-23 14:11:03 +0100387 static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
388 static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100389
390 /* clang-format off */
391 return ManifestDtBuilder()
392 .StartChild("hypervisor")
393 .Compatible()
394 .StartChild("vm1")
395 .DebugName(valid ? last_valid : first_invalid)
396 .EndChild()
397 .EndChild()
398 .Build();
399 /* clang-format on */
400}
401
402TEST(manifest, long_string)
403{
404 struct manifest m;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100405 std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
406 std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
407
David Brazdila2358d42020-01-27 18:51:38 +0000408 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
409 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
410 MANIFEST_ERROR_STRING_TOO_LONG);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100411}
412
413TEST(manifest, reserved_vm_id)
414{
415 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100416
417 /* clang-format off */
418 std::vector<char> dtb = ManifestDtBuilder()
419 .StartChild("hypervisor")
420 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100421 .StartChild("vm1")
422 .DebugName("primary_vm")
423 .EndChild()
424 .StartChild("vm0")
425 .DebugName("reserved_vm")
426 .VcpuCount(1)
427 .MemSize(0x1000)
428 .KernelFilename("kernel")
429 .EndChild()
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_RESERVED_VM_ID);
David Brazdil7a462ec2019-08-15 12:27:47 +0100435}
436
Andrew Scullae9962e2019-10-03 16:51:16 +0100437static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
David Brazdil52256ff2019-08-23 15:15:15 +0100438{
439 /* clang-format off */
440 return ManifestDtBuilder()
441 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100442 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100443 .StartChild("vm1")
444 .DebugName("primary_vm")
445 .EndChild()
446 .StartChild("vm2")
447 .DebugName("secondary_vm")
448 .VcpuCount(vcpu_count)
449 .MemSize(0x1000)
450 .KernelFilename("kernel")
451 .EndChild()
452 .EndChild()
453 .Build();
454 /* clang-format on */
455}
David Brazdil7a462ec2019-08-15 12:27:47 +0100456
457TEST(manifest, vcpu_count_limit)
458{
459 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100460 std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
461 std::vector<char> dtb_first_invalid =
462 gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
David Brazdil7a462ec2019-08-15 12:27:47 +0100463
David Brazdila2358d42020-01-27 18:51:38 +0000464 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100465 ASSERT_EQ(m.vm_count, 2);
David Brazdil7a462ec2019-08-15 12:27:47 +0100466 ASSERT_EQ(m.vm[1].secondary.vcpu_count, UINT16_MAX);
467
David Brazdila2358d42020-01-27 18:51:38 +0000468 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100469 MANIFEST_ERROR_INTEGER_OVERFLOW);
David Brazdil7a462ec2019-08-15 12:27:47 +0100470}
471
David Brazdile6f83222019-09-23 14:47:37 +0100472TEST(manifest, no_ramdisk_primary)
473{
474 struct manifest m;
David Brazdile6f83222019-09-23 14:47:37 +0100475
476 /* clang-format off */
477 std::vector<char> dtb = ManifestDtBuilder()
478 .StartChild("hypervisor")
479 .Compatible()
480 .StartChild("vm1")
481 .DebugName("primary_vm")
482 .EndChild()
483 .EndChild()
484 .Build();
485 /* clang-format on */
486
David Brazdila2358d42020-01-27 18:51:38 +0000487 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdile6f83222019-09-23 14:47:37 +0100488 ASSERT_EQ(m.vm_count, 1);
489 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
490 ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
491}
492
David Brazdil080ee312020-02-25 15:30:30 -0800493TEST(manifest, no_boot_address_primary)
494{
495 struct manifest m;
496
497 /* clang-format off */
498 std::vector<char> dtb = ManifestDtBuilder()
499 .StartChild("hypervisor")
500 .Compatible()
501 .StartChild("vm1")
502 .DebugName("primary_vm")
503 .EndChild()
504 .EndChild()
505 .Build();
506 /* clang-format on */
507
508 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
509 ASSERT_EQ(m.vm_count, 1);
510 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
511 ASSERT_EQ(m.vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
512}
513
514TEST(manifest, boot_address_primary)
515{
516 struct manifest m;
517 const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
518
519 /* clang-format off */
520 std::vector<char> dtb = ManifestDtBuilder()
521 .StartChild("hypervisor")
522 .Compatible()
523 .StartChild("vm1")
524 .DebugName("primary_vm")
525 .BootAddress(addr)
526 .EndChild()
527 .EndChild()
528 .Build();
529 /* clang-format on */
530
531 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
532 ASSERT_EQ(m.vm_count, 1);
533 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
534 ASSERT_EQ(m.vm[0].primary.boot_address, addr);
535}
536
Andrew Scullb2c3a242019-11-04 13:52:36 +0000537static std::vector<char> gen_malformed_boolean_dtb(
538 const std::string_view &value)
Andrew Scullae9962e2019-10-03 16:51:16 +0100539{
Andrew Scullae9962e2019-10-03 16:51:16 +0100540 /* clang-format off */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000541 return ManifestDtBuilder()
Andrew Scullae9962e2019-10-03 16:51:16 +0100542 .StartChild("hypervisor")
543 .Compatible()
544 .StartChild("vm1")
545 .DebugName("primary_vm")
Andrew Scullb2c3a242019-11-04 13:52:36 +0000546 .Property("smc_whitelist_permissive", value)
Andrew Scull5dc089e2019-11-04 13:21:03 +0000547 .EndChild()
Andrew Scullae9962e2019-10-03 16:51:16 +0100548 .EndChild()
549 .Build();
550 /* clang-format on */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000551}
Andrew Scullae9962e2019-10-03 16:51:16 +0100552
Andrew Scullb2c3a242019-11-04 13:52:36 +0000553TEST(manifest, malformed_booleans)
554{
555 struct manifest m;
Andrew Scullae9962e2019-10-03 16:51:16 +0100556
Andrew Scullb2c3a242019-11-04 13:52:36 +0000557 std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
558 std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
559 std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
560 std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
Andrew Scullae9962e2019-10-03 16:51:16 +0100561
David Brazdila2358d42020-01-27 18:51:38 +0000562 ASSERT_EQ(manifest_from_vec(&m, dtb_false),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000563 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000564 ASSERT_EQ(manifest_from_vec(&m, dtb_true),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000565 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000566 ASSERT_EQ(manifest_from_vec(&m, dtb_0),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000567 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000568 ASSERT_EQ(manifest_from_vec(&m, dtb_1),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000569 MANIFEST_ERROR_MALFORMED_BOOLEAN);
Andrew Scullae9962e2019-10-03 16:51:16 +0100570}
571
David Brazdil7a462ec2019-08-15 12:27:47 +0100572TEST(manifest, valid)
573{
574 struct manifest m;
575 struct manifest_vm *vm;
David Brazdil7a462ec2019-08-15 12:27:47 +0100576
David Brazdil52256ff2019-08-23 15:15:15 +0100577 /* clang-format off */
578 std::vector<char> dtb = ManifestDtBuilder()
579 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100580 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100581 .StartChild("vm1")
582 .DebugName("primary_vm")
Andrew Scull72b43c02019-09-18 13:53:45 +0100583 .KernelFilename("primary_kernel")
David Brazdile6f83222019-09-23 14:47:37 +0100584 .RamdiskFilename("primary_ramdisk")
Andrew Scullae9962e2019-10-03 16:51:16 +0100585 .SmcWhitelist({0x32000000, 0x33001111})
David Brazdil52256ff2019-08-23 15:15:15 +0100586 .EndChild()
587 .StartChild("vm3")
588 .DebugName("second_secondary_vm")
589 .VcpuCount(43)
590 .MemSize(0x12345)
Andrew Scull72b43c02019-09-18 13:53:45 +0100591 .KernelFilename("second_secondary_kernel")
David Brazdil52256ff2019-08-23 15:15:15 +0100592 .EndChild()
593 .StartChild("vm2")
594 .DebugName("first_secondary_vm")
595 .VcpuCount(42)
596 .MemSize(12345)
Andrew Scullae9962e2019-10-03 16:51:16 +0100597 .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
598 .SmcWhitelistPermissive()
David Brazdil52256ff2019-08-23 15:15:15 +0100599 .EndChild()
600 .EndChild()
601 .Build();
602 /* clang-format on */
603
David Brazdila2358d42020-01-27 18:51:38 +0000604 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100605 ASSERT_EQ(m.vm_count, 3);
David Brazdil7a462ec2019-08-15 12:27:47 +0100606
607 vm = &m.vm[0];
David Brazdil136f2942019-09-23 14:11:03 +0100608 ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
609 ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
David Brazdile6f83222019-09-23 14:47:37 +0100610 ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
611 "primary_ramdisk");
Andrew Scullae9962e2019-10-03 16:51:16 +0100612 ASSERT_THAT(
613 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
614 ElementsAre(0x32000000, 0x33001111));
615 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100616
617 vm = &m.vm[1];
David Brazdil136f2942019-09-23 14:11:03 +0100618 ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
619 ASSERT_STREQ(string_data(&vm->kernel_filename), "");
David Brazdil7a462ec2019-08-15 12:27:47 +0100620 ASSERT_EQ(vm->secondary.vcpu_count, 42);
621 ASSERT_EQ(vm->secondary.mem_size, 12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100622 ASSERT_THAT(
623 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
624 ElementsAre(0x04000000, 0x30002222, 0x31445566));
625 ASSERT_TRUE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100626
627 vm = &m.vm[2];
David Brazdil136f2942019-09-23 14:11:03 +0100628 ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
629 ASSERT_STREQ(string_data(&vm->kernel_filename),
630 "second_secondary_kernel");
David Brazdil7a462ec2019-08-15 12:27:47 +0100631 ASSERT_EQ(vm->secondary.vcpu_count, 43);
632 ASSERT_EQ(vm->secondary.mem_size, 0x12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100633 ASSERT_THAT(
634 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
635 IsEmpty());
636 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100637}
638
Olivier Deprez62d99e32020-01-09 15:58:07 +0100639/**
640 * Class for programatically building a Partition package.
641 */
642class Partition_package
643{
644 public:
645 __attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
646 char manifest_dtb[PAGE_SIZE] = {};
647
648 Partition_package(const std::vector<char> &vec)
649 {
650 // Initialise header field
651 spkg.magic = SP_PKG_HEADER_MAGIC;
652 spkg.version = SP_PKG_HEADER_VERSION;
653 spkg.pm_offset = sizeof(struct sp_pkg_header);
654 spkg.pm_size = vec.size();
655
656 // Copy dtb into package
657 std::copy(vec.begin(), vec.end(), manifest_dtb);
658 }
659};
660
661static enum manifest_return_code ffa_manifest_from_vec(
662 struct manifest *m, const std::vector<char> &vec)
663{
664 struct memiter it;
665 struct mpool ppool;
666 struct mm_stage1_locked mm_stage1_locked;
667
668 Partition_package spkg(vec);
669
670 /* clang-format off */
671 std::vector<char> core_dtb = ManifestDtBuilder()
672 .StartChild("hypervisor")
673 .Compatible()
674 .StartChild("vm1")
675 .DebugName("primary_vm")
676 .FfaPartition()
677 .LoadAddress((uint64_t)&spkg)
678 .EndChild()
679 .EndChild()
680 .Build();
681 /* clang-format on */
682
683 memiter_init(&it, core_dtb.data(), core_dtb.size());
684 return manifest_init(mm_stage1_locked, m, &it, &ppool);
685}
686
687TEST(manifest, ffa_not_compatible)
688{
689 struct manifest m;
690
691 /* clang-format off */
692 std::vector<char> dtb = ManifestDtBuilder()
693 .Compatible({ "arm,ffa-manifest-2.0" })
694 .Property("ffa-version", "<0x10000>")
695 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
696 .Property("execution-ctx-count", "<1>")
697 .Property("exception-level", "<2>")
698 .Property("execution-state", "<0>")
699 .Property("load-address", "<0x7000000>")
700 .Property("entrypoint-offset", "<0x00001000>")
701 .Property("xlat-granule", "<0>")
702 .Property("messaging-method", "<1>")
703 .Build();
704 /* clang-format on */
705
706 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
707 MANIFEST_ERROR_NOT_COMPATIBLE);
708}
709
710TEST(manifest, ffa_missing_property)
711{
712 struct manifest m;
713
714 /* clang-format off */
715 std::vector<char> dtb = ManifestDtBuilder()
716 .Compatible({ "arm,ffa-manifest-1.0" })
717 .Property("ffa-version", "<0x10000>")
718 .Build();
719 /* clang-format on */
720
721 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
722 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
723}
724
725TEST(manifest, ffa_validate_sanity_check)
726{
727 struct manifest m;
728
729 /* Incompatible version */
730 /* clang-format off */
731 std::vector<char> dtb = ManifestDtBuilder()
732 .Compatible({ "arm,ffa-manifest-1.0" })
733 .Property("ffa-version", "<0xa1>")
734 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
735 .Property("execution-ctx-count", "<1>")
736 .Property("exception-level", "<2>")
737 .Property("execution-state", "<0>")
738 .Property("load-address", "<0x7000000>")
739 .Property("entrypoint-offset", "<0x00001000>")
740 .Property("xlat-granule", "<0>")
741 .Property("messaging-method", "<1>")
742 .Build();
743 /* clang-format on */
744 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
745 MANIFEST_ERROR_NOT_COMPATIBLE);
746
747 /* Incompatible translation granule */
748 /* clang-format off */
749 dtb = ManifestDtBuilder()
750 .Compatible({ "arm,ffa-manifest-1.0" })
751 .Property("ffa-version", "<0x10000>")
752 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
753 .Property("execution-ctx-count", "<1>")
754 .Property("exception-level", "<2>")
755 .Property("execution-state", "<0>")
756 .Property("load-address", "<0x7000000>")
757 .Property("entrypoint-offset", "<0x00001000>")
758 .Property("xlat-granule", "<3>")
759 .Property("messaging-method", "<1>")
760 .Build();
761 /* clang-format on */
762 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
763 MANIFEST_ERROR_NOT_COMPATIBLE);
764
765 /* Incompatible exeption level */
766 /* clang-format off */
767 dtb = ManifestDtBuilder()
768 .Compatible({ "arm,ffa-manifest-1.0" })
769 .Property("ffa-version", "<0x10000>")
770 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
771 .Property("execution-ctx-count", "<1>")
772 .Property("exception-level", "<6>")
773 .Property("execution-state", "<0>")
774 .Property("load-address", "<0x7000000>")
775 .Property("entrypoint-offset", "<0x00001000>")
776 .Property("xlat-granule", "<0>")
777 .Property("messaging-method", "<1>")
778 .Build();
779 /* clang-format on */
780 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
781 MANIFEST_ERROR_NOT_COMPATIBLE);
782
783 /* Incompatible execution state */
784 /* clang-format off */
785 dtb = ManifestDtBuilder()
786 .Compatible({ "arm,ffa-manifest-1.0" })
787 .Property("ffa-version", "<0x10000>")
788 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
789 .Property("execution-ctx-count", "<1>")
790 .Property("exception-level", "<2>")
791 .Property("execution-state", "<2>")
792 .Property("load-address", "<0x7000000>")
793 .Property("entrypoint-offset", "<0x00001000>")
794 .Property("xlat-granule", "<0>")
795 .Property("messaging-method", "<1>")
796 .Build();
797 /* clang-format on */
798 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
799 MANIFEST_ERROR_NOT_COMPATIBLE);
800
801 /* Incompatible messaging method */
802 /* clang-format off */
803 dtb = ManifestDtBuilder()
804 .Compatible({ "arm,ffa-manifest-1.0" })
805 .Property("ffa-version", "<0x10000>")
806 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
807 .Property("execution-ctx-count", "<1>")
808 .Property("exception-level", "<2>")
809 .Property("execution-state", "<0>")
810 .Property("load-address", "<0x7000000>")
811 .Property("entrypoint-offset", "<0x00001000>")
812 .Property("xlat-granule", "<0>")
813 .Property("messaging-method", "<3>")
814 .Build();
815 /* clang-format on */
816 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
817 MANIFEST_ERROR_NOT_COMPATIBLE);
818}
819
Manish Pandey6542f5c2020-04-27 14:37:46 +0100820TEST(manifest, ffa_validate_mem_regions)
821{
822 struct manifest m;
823
824 /* Not Compatible */
825 /* clang-format off */
826 std::vector<char> dtb = ManifestDtBuilder()
827 .FfaValidManifest()
828 .StartChild("memory-regions")
829 .Compatible({ "foo,bar" })
830 .EndChild()
831 .Build();
832 /* clang-format on */
833 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
834 MANIFEST_ERROR_NOT_COMPATIBLE);
835
836 /* Memory regions unavailable */
837 /* clang-format off */
838 dtb = ManifestDtBuilder()
839 .FfaValidManifest()
840 .StartChild("memory-regions")
841 .Compatible({ "arm,ffa-manifest-memory-regions" })
842 .EndChild()
843 .Build();
844 /* clang-format on */
845 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
846 MANIFEST_ERROR_MEMORY_REGION_NODE_EMPTY);
847
848 /* Missing Properties */
849 /* clang-format off */
850 dtb = ManifestDtBuilder()
851 .FfaValidManifest()
852 .StartChild("memory-regions")
853 .Compatible({ "arm,ffa-manifest-memory-regions" })
854 .StartChild("test-memory")
855 .Description("test-memory")
856 .EndChild()
857 .EndChild()
858 .Build();
859 /* clang-format on */
860 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
861 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
862}
863
Manish Pandeye68e7932020-04-23 15:29:28 +0100864TEST(manifest, ffa_validate_dev_regions)
865{
866 struct manifest m;
867
868 /* Not Compatible */
869 /* clang-format off */
870 std::vector<char> dtb = ManifestDtBuilder()
871 .FfaValidManifest()
872 .StartChild("device-regions")
873 .Compatible({ "foo,bar" })
874 .EndChild()
875 .Build();
876 /* clang-format on */
877 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
878 MANIFEST_ERROR_NOT_COMPATIBLE);
879
880 /* Memory regions unavailable */
881 /* clang-format off */
882 dtb = ManifestDtBuilder()
883 .FfaValidManifest()
884 .StartChild("device-regions")
885 .Compatible({ "arm,ffa-manifest-device-regions" })
886 .EndChild()
887 .Build();
888 /* clang-format on */
889 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
890 MANIFEST_ERROR_DEVICE_REGION_NODE_EMPTY);
891
892 /* Missing Properties */
893 /* clang-format off */
894 dtb = ManifestDtBuilder()
895 .FfaValidManifest()
896 .StartChild("device-regions")
897 .Compatible({ "arm,ffa-manifest-device-regions" })
898 .StartChild("test-device")
899 .Description("test-device")
900 .EndChild()
901 .EndChild()
902 .Build();
903 /* clang-format on */
904 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
905 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
906
907 /* Malformed interrupt list pair */
908 /* clang-format off */
909 dtb = ManifestDtBuilder()
910 .FfaValidManifest()
911 .StartChild("device-regions")
912 .Compatible({ "arm,ffa-manifest-device-regions" })
913 .StartChild("test-device")
914 .Description("test-device")
915 .Property("base-address", "<0x7200000>")
916 .Property("pages-count", "<16>")
917 .Property("attributes", "<3>")
918 .Property("smmu-id", "<1>")
919 .Property("stream-ids", "<0 1>")
920 .Property("interrupts", "<2 3>, <4>")
921 .EndChild()
922 .EndChild()
923 .Build();
924 /* clang-format on */
925 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
926 MANIFEST_ERROR_MALFORMED_INTEGER_LIST);
927}
928
Olivier Deprez62d99e32020-01-09 15:58:07 +0100929TEST(manifest, ffa_valid)
930{
931 struct manifest m;
932
933 /* clang-format off */
934 std::vector<char> dtb = ManifestDtBuilder()
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100935 .FfaValidManifest()
Manish Pandey6542f5c2020-04-27 14:37:46 +0100936 .StartChild("memory-regions")
937 .Compatible({ "arm,ffa-manifest-memory-regions" })
938 .StartChild("test-memory")
939 .Description("test-memory")
940 .Property("base-address", "<0x7100000>")
941 .Property("pages-count", "<4>")
942 .Property("attributes", "<7>")
943 .EndChild()
944 .EndChild()
Manish Pandeye68e7932020-04-23 15:29:28 +0100945 .StartChild("device-regions")
946 .Compatible({ "arm,ffa-manifest-device-regions" })
947 .StartChild("test-device")
948 .Description("test-device")
949 .Property("base-address", "<0x7200000>")
950 .Property("pages-count", "<16>")
951 .Property("attributes", "<3>")
952 .Property("smmu-id", "<1>")
953 .Property("stream-ids", "<0 1>")
954 .Property("interrupts", "<2 3>, <4 5>")
955 .EndChild()
956 .EndChild()
Olivier Deprez62d99e32020-01-09 15:58:07 +0100957 .Build();
958 /* clang-format on */
959
960 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
961
962 ASSERT_EQ(m.vm[0].sp.ffa_version, 0x10000);
963 ASSERT_THAT(
Fuad Tabbae4efcc32020-07-16 15:37:27 +0100964 std::span(m.vm[0].sp.uuid.uuid, 4),
Olivier Deprez62d99e32020-01-09 15:58:07 +0100965 ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb));
966 ASSERT_EQ(m.vm[0].sp.execution_ctx_count, 1);
967 ASSERT_EQ(m.vm[0].sp.run_time_el, S_EL1);
968 ASSERT_EQ(m.vm[0].sp.execution_state, AARCH64);
969 ASSERT_EQ(m.vm[0].sp.load_addr, 0x7000000);
970 ASSERT_EQ(m.vm[0].sp.ep_offset, 0x00001000);
971 ASSERT_EQ(m.vm[0].sp.xlat_granule, PAGE_4KB);
972 ASSERT_EQ(m.vm[0].sp.messaging_method, INDIRECT_MESSAGING);
Manish Pandey6542f5c2020-04-27 14:37:46 +0100973 ASSERT_EQ(m.vm[0].sp.mem_regions[0].base_address, 0x7100000);
974 ASSERT_EQ(m.vm[0].sp.mem_regions[0].page_count, 4);
975 ASSERT_EQ(m.vm[0].sp.mem_regions[0].attributes, 7);
Manish Pandeye68e7932020-04-23 15:29:28 +0100976 ASSERT_EQ(m.vm[0].sp.dev_regions[0].base_address, 0x7200000);
977 ASSERT_EQ(m.vm[0].sp.dev_regions[0].page_count, 16);
978 /* Attribute is ORed with MM_MODE_D */
979 ASSERT_EQ(m.vm[0].sp.dev_regions[0].attributes, (3 | 8));
980 ASSERT_EQ(m.vm[0].sp.dev_regions[0].smmu_id, 1);
981 ASSERT_EQ(m.vm[0].sp.dev_regions[0].stream_ids[0], 0);
982 ASSERT_EQ(m.vm[0].sp.dev_regions[0].stream_ids[1], 1);
983 ASSERT_EQ(m.vm[0].sp.dev_regions[0].interrupts[0].id, 2);
984 ASSERT_EQ(m.vm[0].sp.dev_regions[0].interrupts[0].attributes, 3);
985 ASSERT_EQ(m.vm[0].sp.dev_regions[0].interrupts[1].id, 4);
986 ASSERT_EQ(m.vm[0].sp.dev_regions[0].interrupts[1].attributes, 5);
Olivier Deprez62d99e32020-01-09 15:58:07 +0100987}
988
David Brazdil7a462ec2019-08-15 12:27:47 +0100989} /* namespace */