blob: 5ac6a31a2d715a0cd251028574c03c600f3ece5f [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
163 ManifestDtBuilder &KernelFilename(const std::string_view &value)
164 {
165 return StringProperty("kernel_filename", value);
166 }
167
David Brazdile6f83222019-09-23 14:47:37 +0100168 ManifestDtBuilder &RamdiskFilename(const std::string_view &value)
169 {
170 return StringProperty("ramdisk_filename", value);
171 }
172
David Brazdil080ee312020-02-25 15:30:30 -0800173 ManifestDtBuilder &BootAddress(uint64_t value)
174 {
175 return Integer64Property("boot_address", value);
176 }
177
Andrew Scullae9962e2019-10-03 16:51:16 +0100178 ManifestDtBuilder &VcpuCount(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100179 {
180 return IntegerProperty("vcpu_count", value);
181 }
182
Andrew Scullae9962e2019-10-03 16:51:16 +0100183 ManifestDtBuilder &MemSize(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100184 {
185 return IntegerProperty("mem_size", value);
186 }
187
Andrew Scullae9962e2019-10-03 16:51:16 +0100188 ManifestDtBuilder &SmcWhitelist(const std::vector<uint32_t> &value)
189 {
190 return IntegerListProperty("smc_whitelist", value);
191 }
192
193 ManifestDtBuilder &SmcWhitelistPermissive()
194 {
195 return BooleanProperty("smc_whitelist_permissive");
196 }
197
Olivier Deprez62d99e32020-01-09 15:58:07 +0100198 ManifestDtBuilder &LoadAddress(uint64_t value)
199 {
200 return Integer64Property("load_address", value);
201 }
202
203 ManifestDtBuilder &FfaPartition()
204 {
205 return BooleanProperty("is_ffa_partition");
206 }
207
Andrew Scullae9962e2019-10-03 16:51:16 +0100208 ManifestDtBuilder &Property(const std::string_view &name,
209 const std::string_view &value)
210 {
211 dts_ << name << " = " << value << ";" << std::endl;
212 return *this;
213 }
214
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100215 ManifestDtBuilder &FfaValidManifest()
216 {
217 Compatible({"arm,ffa-manifest-1.0"});
218 Property("ffa-version", "<0x10000>");
219 Property("uuid",
220 "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>");
221 Property("execution-ctx-count", "<1>");
222 Property("exception-level", "<2>");
223 Property("execution-state", "<0>");
224 Property("load-address", "<0x7000000>");
225 Property("entrypoint-offset", "<0x00001000>");
226 Property("xlat-granule", "<0>");
227 Property("messaging-method", "<1>");
228 return *this;
229 }
230
David Brazdil52256ff2019-08-23 15:15:15 +0100231 private:
232 ManifestDtBuilder &StringProperty(const std::string_view &name,
233 const std::string_view &value)
234 {
235 dts_ << name << " = \"" << value << "\";" << std::endl;
236 return *this;
237 }
238
David Brazdil74e9c3b2019-08-28 11:09:08 +0100239 ManifestDtBuilder &StringListProperty(
240 const std::string_view &name,
241 const std::vector<std::string_view> &value)
242 {
243 bool is_first = true;
244
245 dts_ << name << " = ";
246 for (const std::string_view &entry : value) {
247 if (is_first) {
248 is_first = false;
249 } else {
250 dts_ << ", ";
251 }
252 dts_ << "\"" << entry << "\"";
253 }
254 dts_ << ";" << std::endl;
255 return *this;
256 }
257
David Brazdil52256ff2019-08-23 15:15:15 +0100258 ManifestDtBuilder &IntegerProperty(const std::string_view &name,
Andrew Scullae9962e2019-10-03 16:51:16 +0100259 uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100260 {
261 dts_ << name << " = <" << value << ">;" << std::endl;
262 return *this;
263 }
264
David Brazdil080ee312020-02-25 15:30:30 -0800265 ManifestDtBuilder &Integer64Property(const std::string_view &name,
266 uint64_t value)
267 {
268 uint32_t high = value >> 32;
269 uint32_t low = (uint32_t)value;
270 dts_ << name << " = <" << high << " " << low << ">;"
271 << std::endl;
272 return *this;
273 }
274
Andrew Scullae9962e2019-10-03 16:51:16 +0100275 ManifestDtBuilder &IntegerListProperty(
276 const std::string_view &name,
277 const std::vector<uint32_t> &value)
278 {
279 dts_ << name << " = < ";
280 for (const uint32_t entry : value) {
281 dts_ << entry << " ";
282 }
283 dts_ << ">;" << std::endl;
284 return *this;
285 }
286
287 ManifestDtBuilder &BooleanProperty(const std::string_view &name)
288 {
Andrew Scull5dc089e2019-11-04 13:21:03 +0000289 dts_ << name << ";" << std::endl;
290 return *this;
Andrew Scullae9962e2019-10-03 16:51:16 +0100291 }
292
David Brazdil52256ff2019-08-23 15:15:15 +0100293 std::stringstream dts_;
294};
295
David Brazdila2358d42020-01-27 18:51:38 +0000296static enum manifest_return_code manifest_from_vec(struct manifest *m,
297 const std::vector<char> &vec)
David Brazdil0dbb41f2019-09-09 18:03:35 +0100298{
David Brazdila2358d42020-01-27 18:51:38 +0000299 struct memiter it;
Olivier Deprez62d99e32020-01-09 15:58:07 +0100300 struct mpool ppool;
301 struct mm_stage1_locked mm_stage1_locked;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100302
David Brazdila2358d42020-01-27 18:51:38 +0000303 memiter_init(&it, vec.data(), vec.size());
Olivier Deprez62d99e32020-01-09 15:58:07 +0100304 return manifest_init(mm_stage1_locked, m, &it, &ppool);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100305}
306
David Brazdil52256ff2019-08-23 15:15:15 +0100307TEST(manifest, no_hypervisor_node)
David Brazdil7a462ec2019-08-15 12:27:47 +0100308{
309 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100310 std::vector<char> dtb = ManifestDtBuilder().Build();
David Brazdil7a462ec2019-08-15 12:27:47 +0100311
David Brazdila2358d42020-01-27 18:51:38 +0000312 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil7a462ec2019-08-15 12:27:47 +0100313 MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
314}
315
David Brazdil74e9c3b2019-08-28 11:09:08 +0100316TEST(manifest, no_compatible_property)
David Brazdil7a462ec2019-08-15 12:27:47 +0100317{
318 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100319
David Brazdil52256ff2019-08-23 15:15:15 +0100320 /* clang-format off */
321 std::vector<char> dtb = ManifestDtBuilder()
322 .StartChild("hypervisor")
323 .EndChild()
324 .Build();
325 /* clang-format on */
326
David Brazdilf4925382020-03-25 13:33:51 +0000327 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil7a462ec2019-08-15 12:27:47 +0100328}
329
David Brazdil74e9c3b2019-08-28 11:09:08 +0100330TEST(manifest, not_compatible)
David Brazdil7a462ec2019-08-15 12:27:47 +0100331{
332 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100333
David Brazdil52256ff2019-08-23 15:15:15 +0100334 /* clang-format off */
335 std::vector<char> dtb = ManifestDtBuilder()
336 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100337 .Compatible({ "foo,bar" })
338 .EndChild()
339 .Build();
340 /* clang-format on */
341
David Brazdila2358d42020-01-27 18:51:38 +0000342 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100343}
344
345TEST(manifest, compatible_one_of_many)
346{
347 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100348
349 /* clang-format off */
350 std::vector<char> dtb = ManifestDtBuilder()
351 .StartChild("hypervisor")
352 .Compatible({ "foo,bar", "hafnium,hafnium" })
353 .StartChild("vm1")
354 .DebugName("primary")
355 .EndChild()
356 .EndChild()
357 .Build();
358 /* clang-format on */
359
David Brazdila2358d42020-01-27 18:51:38 +0000360 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100361}
362
363TEST(manifest, no_vm_nodes)
364{
365 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100366
367 /* clang-format off */
368 std::vector<char> dtb = ManifestDtBuilder()
369 .StartChild("hypervisor")
370 .Compatible()
371 .EndChild()
372 .Build();
373 /* clang-format on */
374
David Brazdila2358d42020-01-27 18:51:38 +0000375 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NO_PRIMARY_VM);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100376}
377
378static std::vector<char> gen_long_string_dtb(bool valid)
379{
380 const char last_valid[] = "1234567890123456789012345678901";
381 const char first_invalid[] = "12345678901234567890123456789012";
David Brazdil136f2942019-09-23 14:11:03 +0100382 static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
383 static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100384
385 /* clang-format off */
386 return ManifestDtBuilder()
387 .StartChild("hypervisor")
388 .Compatible()
389 .StartChild("vm1")
390 .DebugName(valid ? last_valid : first_invalid)
391 .EndChild()
392 .EndChild()
393 .Build();
394 /* clang-format on */
395}
396
397TEST(manifest, long_string)
398{
399 struct manifest m;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100400 std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
401 std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
402
David Brazdila2358d42020-01-27 18:51:38 +0000403 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
404 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
405 MANIFEST_ERROR_STRING_TOO_LONG);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100406}
407
408TEST(manifest, reserved_vm_id)
409{
410 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100411
412 /* clang-format off */
413 std::vector<char> dtb = ManifestDtBuilder()
414 .StartChild("hypervisor")
415 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100416 .StartChild("vm1")
417 .DebugName("primary_vm")
418 .EndChild()
419 .StartChild("vm0")
420 .DebugName("reserved_vm")
421 .VcpuCount(1)
422 .MemSize(0x1000)
423 .KernelFilename("kernel")
424 .EndChild()
425 .EndChild()
426 .Build();
427 /* clang-format on */
428
David Brazdila2358d42020-01-27 18:51:38 +0000429 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_RESERVED_VM_ID);
David Brazdil7a462ec2019-08-15 12:27:47 +0100430}
431
Andrew Scullae9962e2019-10-03 16:51:16 +0100432static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
David Brazdil52256ff2019-08-23 15:15:15 +0100433{
434 /* clang-format off */
435 return ManifestDtBuilder()
436 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100437 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100438 .StartChild("vm1")
439 .DebugName("primary_vm")
440 .EndChild()
441 .StartChild("vm2")
442 .DebugName("secondary_vm")
443 .VcpuCount(vcpu_count)
444 .MemSize(0x1000)
445 .KernelFilename("kernel")
446 .EndChild()
447 .EndChild()
448 .Build();
449 /* clang-format on */
450}
David Brazdil7a462ec2019-08-15 12:27:47 +0100451
452TEST(manifest, vcpu_count_limit)
453{
454 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100455 std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
456 std::vector<char> dtb_first_invalid =
457 gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
David Brazdil7a462ec2019-08-15 12:27:47 +0100458
David Brazdila2358d42020-01-27 18:51:38 +0000459 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100460 ASSERT_EQ(m.vm_count, 2);
David Brazdil7a462ec2019-08-15 12:27:47 +0100461 ASSERT_EQ(m.vm[1].secondary.vcpu_count, UINT16_MAX);
462
David Brazdila2358d42020-01-27 18:51:38 +0000463 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100464 MANIFEST_ERROR_INTEGER_OVERFLOW);
David Brazdil7a462ec2019-08-15 12:27:47 +0100465}
466
David Brazdile6f83222019-09-23 14:47:37 +0100467TEST(manifest, no_ramdisk_primary)
468{
469 struct manifest m;
David Brazdile6f83222019-09-23 14:47:37 +0100470
471 /* clang-format off */
472 std::vector<char> dtb = ManifestDtBuilder()
473 .StartChild("hypervisor")
474 .Compatible()
475 .StartChild("vm1")
476 .DebugName("primary_vm")
477 .EndChild()
478 .EndChild()
479 .Build();
480 /* clang-format on */
481
David Brazdila2358d42020-01-27 18:51:38 +0000482 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdile6f83222019-09-23 14:47:37 +0100483 ASSERT_EQ(m.vm_count, 1);
484 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
485 ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
486}
487
David Brazdil080ee312020-02-25 15:30:30 -0800488TEST(manifest, no_boot_address_primary)
489{
490 struct manifest m;
491
492 /* clang-format off */
493 std::vector<char> dtb = ManifestDtBuilder()
494 .StartChild("hypervisor")
495 .Compatible()
496 .StartChild("vm1")
497 .DebugName("primary_vm")
498 .EndChild()
499 .EndChild()
500 .Build();
501 /* clang-format on */
502
503 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
504 ASSERT_EQ(m.vm_count, 1);
505 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
506 ASSERT_EQ(m.vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
507}
508
509TEST(manifest, boot_address_primary)
510{
511 struct manifest m;
512 const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
513
514 /* clang-format off */
515 std::vector<char> dtb = ManifestDtBuilder()
516 .StartChild("hypervisor")
517 .Compatible()
518 .StartChild("vm1")
519 .DebugName("primary_vm")
520 .BootAddress(addr)
521 .EndChild()
522 .EndChild()
523 .Build();
524 /* clang-format on */
525
526 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
527 ASSERT_EQ(m.vm_count, 1);
528 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
529 ASSERT_EQ(m.vm[0].primary.boot_address, addr);
530}
531
Andrew Scullb2c3a242019-11-04 13:52:36 +0000532static std::vector<char> gen_malformed_boolean_dtb(
533 const std::string_view &value)
Andrew Scullae9962e2019-10-03 16:51:16 +0100534{
Andrew Scullae9962e2019-10-03 16:51:16 +0100535 /* clang-format off */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000536 return ManifestDtBuilder()
Andrew Scullae9962e2019-10-03 16:51:16 +0100537 .StartChild("hypervisor")
538 .Compatible()
539 .StartChild("vm1")
540 .DebugName("primary_vm")
Andrew Scullb2c3a242019-11-04 13:52:36 +0000541 .Property("smc_whitelist_permissive", value)
Andrew Scull5dc089e2019-11-04 13:21:03 +0000542 .EndChild()
Andrew Scullae9962e2019-10-03 16:51:16 +0100543 .EndChild()
544 .Build();
545 /* clang-format on */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000546}
Andrew Scullae9962e2019-10-03 16:51:16 +0100547
Andrew Scullb2c3a242019-11-04 13:52:36 +0000548TEST(manifest, malformed_booleans)
549{
550 struct manifest m;
Andrew Scullae9962e2019-10-03 16:51:16 +0100551
Andrew Scullb2c3a242019-11-04 13:52:36 +0000552 std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
553 std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
554 std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
555 std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
Andrew Scullae9962e2019-10-03 16:51:16 +0100556
David Brazdila2358d42020-01-27 18:51:38 +0000557 ASSERT_EQ(manifest_from_vec(&m, dtb_false),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000558 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000559 ASSERT_EQ(manifest_from_vec(&m, dtb_true),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000560 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000561 ASSERT_EQ(manifest_from_vec(&m, dtb_0),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000562 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000563 ASSERT_EQ(manifest_from_vec(&m, dtb_1),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000564 MANIFEST_ERROR_MALFORMED_BOOLEAN);
Andrew Scullae9962e2019-10-03 16:51:16 +0100565}
566
David Brazdil7a462ec2019-08-15 12:27:47 +0100567TEST(manifest, valid)
568{
569 struct manifest m;
570 struct manifest_vm *vm;
David Brazdil7a462ec2019-08-15 12:27:47 +0100571
David Brazdil52256ff2019-08-23 15:15:15 +0100572 /* clang-format off */
573 std::vector<char> dtb = ManifestDtBuilder()
574 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100575 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100576 .StartChild("vm1")
577 .DebugName("primary_vm")
Andrew Scull72b43c02019-09-18 13:53:45 +0100578 .KernelFilename("primary_kernel")
David Brazdile6f83222019-09-23 14:47:37 +0100579 .RamdiskFilename("primary_ramdisk")
Andrew Scullae9962e2019-10-03 16:51:16 +0100580 .SmcWhitelist({0x32000000, 0x33001111})
David Brazdil52256ff2019-08-23 15:15:15 +0100581 .EndChild()
582 .StartChild("vm3")
583 .DebugName("second_secondary_vm")
584 .VcpuCount(43)
585 .MemSize(0x12345)
Andrew Scull72b43c02019-09-18 13:53:45 +0100586 .KernelFilename("second_secondary_kernel")
David Brazdil52256ff2019-08-23 15:15:15 +0100587 .EndChild()
588 .StartChild("vm2")
589 .DebugName("first_secondary_vm")
590 .VcpuCount(42)
591 .MemSize(12345)
Andrew Scullae9962e2019-10-03 16:51:16 +0100592 .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
593 .SmcWhitelistPermissive()
David Brazdil52256ff2019-08-23 15:15:15 +0100594 .EndChild()
595 .EndChild()
596 .Build();
597 /* clang-format on */
598
David Brazdila2358d42020-01-27 18:51:38 +0000599 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100600 ASSERT_EQ(m.vm_count, 3);
David Brazdil7a462ec2019-08-15 12:27:47 +0100601
602 vm = &m.vm[0];
David Brazdil136f2942019-09-23 14:11:03 +0100603 ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
604 ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
David Brazdile6f83222019-09-23 14:47:37 +0100605 ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
606 "primary_ramdisk");
Andrew Scullae9962e2019-10-03 16:51:16 +0100607 ASSERT_THAT(
608 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
609 ElementsAre(0x32000000, 0x33001111));
610 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100611
612 vm = &m.vm[1];
David Brazdil136f2942019-09-23 14:11:03 +0100613 ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
614 ASSERT_STREQ(string_data(&vm->kernel_filename), "");
David Brazdil7a462ec2019-08-15 12:27:47 +0100615 ASSERT_EQ(vm->secondary.vcpu_count, 42);
616 ASSERT_EQ(vm->secondary.mem_size, 12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100617 ASSERT_THAT(
618 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
619 ElementsAre(0x04000000, 0x30002222, 0x31445566));
620 ASSERT_TRUE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100621
622 vm = &m.vm[2];
David Brazdil136f2942019-09-23 14:11:03 +0100623 ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
624 ASSERT_STREQ(string_data(&vm->kernel_filename),
625 "second_secondary_kernel");
David Brazdil7a462ec2019-08-15 12:27:47 +0100626 ASSERT_EQ(vm->secondary.vcpu_count, 43);
627 ASSERT_EQ(vm->secondary.mem_size, 0x12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100628 ASSERT_THAT(
629 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
630 IsEmpty());
631 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100632}
633
Olivier Deprez62d99e32020-01-09 15:58:07 +0100634/**
635 * Class for programatically building a Partition package.
636 */
637class Partition_package
638{
639 public:
640 __attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
641 char manifest_dtb[PAGE_SIZE] = {};
642
643 Partition_package(const std::vector<char> &vec)
644 {
645 // Initialise header field
646 spkg.magic = SP_PKG_HEADER_MAGIC;
647 spkg.version = SP_PKG_HEADER_VERSION;
648 spkg.pm_offset = sizeof(struct sp_pkg_header);
649 spkg.pm_size = vec.size();
650
651 // Copy dtb into package
652 std::copy(vec.begin(), vec.end(), manifest_dtb);
653 }
654};
655
656static enum manifest_return_code ffa_manifest_from_vec(
657 struct manifest *m, const std::vector<char> &vec)
658{
659 struct memiter it;
660 struct mpool ppool;
661 struct mm_stage1_locked mm_stage1_locked;
662
663 Partition_package spkg(vec);
664
665 /* clang-format off */
666 std::vector<char> core_dtb = ManifestDtBuilder()
667 .StartChild("hypervisor")
668 .Compatible()
669 .StartChild("vm1")
670 .DebugName("primary_vm")
671 .FfaPartition()
672 .LoadAddress((uint64_t)&spkg)
673 .EndChild()
674 .EndChild()
675 .Build();
676 /* clang-format on */
677
678 memiter_init(&it, core_dtb.data(), core_dtb.size());
679 return manifest_init(mm_stage1_locked, m, &it, &ppool);
680}
681
682TEST(manifest, ffa_not_compatible)
683{
684 struct manifest m;
685
686 /* clang-format off */
687 std::vector<char> dtb = ManifestDtBuilder()
688 .Compatible({ "arm,ffa-manifest-2.0" })
689 .Property("ffa-version", "<0x10000>")
690 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
691 .Property("execution-ctx-count", "<1>")
692 .Property("exception-level", "<2>")
693 .Property("execution-state", "<0>")
694 .Property("load-address", "<0x7000000>")
695 .Property("entrypoint-offset", "<0x00001000>")
696 .Property("xlat-granule", "<0>")
697 .Property("messaging-method", "<1>")
698 .Build();
699 /* clang-format on */
700
701 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
702 MANIFEST_ERROR_NOT_COMPATIBLE);
703}
704
705TEST(manifest, ffa_missing_property)
706{
707 struct manifest m;
708
709 /* clang-format off */
710 std::vector<char> dtb = ManifestDtBuilder()
711 .Compatible({ "arm,ffa-manifest-1.0" })
712 .Property("ffa-version", "<0x10000>")
713 .Build();
714 /* clang-format on */
715
716 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
717 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
718}
719
720TEST(manifest, ffa_validate_sanity_check)
721{
722 struct manifest m;
723
724 /* Incompatible version */
725 /* clang-format off */
726 std::vector<char> dtb = ManifestDtBuilder()
727 .Compatible({ "arm,ffa-manifest-1.0" })
728 .Property("ffa-version", "<0xa1>")
729 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
730 .Property("execution-ctx-count", "<1>")
731 .Property("exception-level", "<2>")
732 .Property("execution-state", "<0>")
733 .Property("load-address", "<0x7000000>")
734 .Property("entrypoint-offset", "<0x00001000>")
735 .Property("xlat-granule", "<0>")
736 .Property("messaging-method", "<1>")
737 .Build();
738 /* clang-format on */
739 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
740 MANIFEST_ERROR_NOT_COMPATIBLE);
741
742 /* Incompatible translation granule */
743 /* clang-format off */
744 dtb = ManifestDtBuilder()
745 .Compatible({ "arm,ffa-manifest-1.0" })
746 .Property("ffa-version", "<0x10000>")
747 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
748 .Property("execution-ctx-count", "<1>")
749 .Property("exception-level", "<2>")
750 .Property("execution-state", "<0>")
751 .Property("load-address", "<0x7000000>")
752 .Property("entrypoint-offset", "<0x00001000>")
753 .Property("xlat-granule", "<3>")
754 .Property("messaging-method", "<1>")
755 .Build();
756 /* clang-format on */
757 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
758 MANIFEST_ERROR_NOT_COMPATIBLE);
759
760 /* Incompatible exeption level */
761 /* clang-format off */
762 dtb = ManifestDtBuilder()
763 .Compatible({ "arm,ffa-manifest-1.0" })
764 .Property("ffa-version", "<0x10000>")
765 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
766 .Property("execution-ctx-count", "<1>")
767 .Property("exception-level", "<6>")
768 .Property("execution-state", "<0>")
769 .Property("load-address", "<0x7000000>")
770 .Property("entrypoint-offset", "<0x00001000>")
771 .Property("xlat-granule", "<0>")
772 .Property("messaging-method", "<1>")
773 .Build();
774 /* clang-format on */
775 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
776 MANIFEST_ERROR_NOT_COMPATIBLE);
777
778 /* Incompatible execution state */
779 /* clang-format off */
780 dtb = ManifestDtBuilder()
781 .Compatible({ "arm,ffa-manifest-1.0" })
782 .Property("ffa-version", "<0x10000>")
783 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
784 .Property("execution-ctx-count", "<1>")
785 .Property("exception-level", "<2>")
786 .Property("execution-state", "<2>")
787 .Property("load-address", "<0x7000000>")
788 .Property("entrypoint-offset", "<0x00001000>")
789 .Property("xlat-granule", "<0>")
790 .Property("messaging-method", "<1>")
791 .Build();
792 /* clang-format on */
793 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
794 MANIFEST_ERROR_NOT_COMPATIBLE);
795
796 /* Incompatible messaging method */
797 /* clang-format off */
798 dtb = ManifestDtBuilder()
799 .Compatible({ "arm,ffa-manifest-1.0" })
800 .Property("ffa-version", "<0x10000>")
801 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
802 .Property("execution-ctx-count", "<1>")
803 .Property("exception-level", "<2>")
804 .Property("execution-state", "<0>")
805 .Property("load-address", "<0x7000000>")
806 .Property("entrypoint-offset", "<0x00001000>")
807 .Property("xlat-granule", "<0>")
808 .Property("messaging-method", "<3>")
809 .Build();
810 /* clang-format on */
811 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
812 MANIFEST_ERROR_NOT_COMPATIBLE);
813}
814
815TEST(manifest, ffa_valid)
816{
817 struct manifest m;
818
819 /* clang-format off */
820 std::vector<char> dtb = ManifestDtBuilder()
Manish Pandeycb8fbb22020-08-18 00:04:43 +0100821 .FfaValidManifest()
Olivier Deprez62d99e32020-01-09 15:58:07 +0100822 .Build();
823 /* clang-format on */
824
825 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
826
827 ASSERT_EQ(m.vm[0].sp.ffa_version, 0x10000);
828 ASSERT_THAT(
Fuad Tabbae4efcc32020-07-16 15:37:27 +0100829 std::span(m.vm[0].sp.uuid.uuid, 4),
Olivier Deprez62d99e32020-01-09 15:58:07 +0100830 ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb));
831 ASSERT_EQ(m.vm[0].sp.execution_ctx_count, 1);
832 ASSERT_EQ(m.vm[0].sp.run_time_el, S_EL1);
833 ASSERT_EQ(m.vm[0].sp.execution_state, AARCH64);
834 ASSERT_EQ(m.vm[0].sp.load_addr, 0x7000000);
835 ASSERT_EQ(m.vm[0].sp.ep_offset, 0x00001000);
836 ASSERT_EQ(m.vm[0].sp.xlat_granule, PAGE_4KB);
837 ASSERT_EQ(m.vm[0].sp.messaging_method, INDIRECT_MESSAGING);
838}
839
David Brazdil7a462ec2019-08-15 12:27:47 +0100840} /* namespace */