blob: 99665a2f6023d220bb813e887e6f9a5f19fbb610 [file] [log] [blame]
David Brazdil7a462ec2019-08-15 12:27:47 +01001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
David Brazdil52256ff2019-08-23 15:15:15 +010017#include <array>
18#include <cstdio>
Andrew Scullae9962e2019-10-03 16:51:16 +010019#include <span>
David Brazdil52256ff2019-08-23 15:15:15 +010020#include <sstream>
21
David Brazdil7a462ec2019-08-15 12:27:47 +010022#include <gmock/gmock.h>
23
24extern "C" {
25#include "hf/manifest.h"
26}
27
28namespace
29{
Andrew Scullae9962e2019-10-03 16:51:16 +010030using ::testing::ElementsAre;
David Brazdil7a462ec2019-08-15 12:27:47 +010031using ::testing::Eq;
Andrew Scullae9962e2019-10-03 16:51:16 +010032using ::testing::IsEmpty;
David Brazdil7a462ec2019-08-15 12:27:47 +010033using ::testing::NotNull;
34
David Brazdil52256ff2019-08-23 15:15:15 +010035template <typename T>
David Brazdil0dbb41f2019-09-09 18:03:35 +010036void exec(const char *program, const char *args[], const T &stdin,
David Brazdil52256ff2019-08-23 15:15:15 +010037 std::vector<char> *stdout)
38{
39 /* Create two pipes, one for stdin and one for stdout. */
40 int pipes[2][2];
41 pipe(pipes[0]);
42 pipe(pipes[1]);
David Brazdil7a462ec2019-08-15 12:27:47 +010043
David Brazdil52256ff2019-08-23 15:15:15 +010044 /* Assign FDs for reading/writing by the parent/child. */
45 int parent_read_fd = pipes[1][0]; /* stdout pipe, read FD */
46 int parent_write_fd = pipes[0][1]; /* stdin pipe, write FD */
47 int child_read_fd = pipes[0][0]; /* stdin pipe, read FD */
48 int child_write_fd = pipes[1][1]; /* stdout pipe, write FD */
David Brazdil7a462ec2019-08-15 12:27:47 +010049
David Brazdil52256ff2019-08-23 15:15:15 +010050 if (fork()) {
51 /* Parent process. */
52 std::array<char, 128> buf;
53 ssize_t res;
54
55 /* Close child FDs which won't be used. */
56 close(child_read_fd);
57 close(child_write_fd);
58
59 /* Write to stdin. */
60 for (size_t count = 0; count < stdin.size();) {
61 res = write(parent_write_fd, stdin.data() + count,
62 stdin.size() - count);
63 if (res < 0) {
64 std::cerr << "IO error" << std::endl;
65 exit(1);
66 }
67 count += res;
68 }
69 close(parent_write_fd);
70
71 /* Read from stdout. */
72 while (true) {
73 res = read(parent_read_fd, buf.data(), buf.size());
74 if (res == 0) {
75 /* EOF */
76 break;
77 } else if (res < 0) {
78 std::cerr << "IO error" << std::endl;
79 exit(1);
80 }
81 stdout->insert(stdout->end(), buf.begin(),
82 buf.begin() + res);
83 }
84 close(parent_read_fd);
85 } else {
86 /* Child process. */
87
88 /* Redirect stdin/stdout to read/write FDs. */
89 dup2(child_read_fd, STDIN_FILENO);
90 dup2(child_write_fd, STDOUT_FILENO);
91
92 /* Close all FDs which are now unused. */
93 close(child_read_fd);
94 close(child_write_fd);
95 close(parent_read_fd);
96 close(parent_write_fd);
97
98 /* Execute the given program. */
David Brazdil0dbb41f2019-09-09 18:03:35 +010099 execv(program, const_cast<char *const *>(args));
David Brazdil52256ff2019-08-23 15:15:15 +0100100 }
101}
102
103/**
104 * Class for programatically building a Device Tree.
105 *
106 * Usage:
107 * std::vector<char> dtb = ManifestDtBuilder()
108 * .Command1()
109 * .Command2()
110 * ...
111 * .CommandN()
112 * .Build();
113 */
114class ManifestDtBuilder
115{
116 public:
117 ManifestDtBuilder()
118 {
119 dts_ << "/dts-v1/;" << std::endl;
120 dts_ << std::endl;
121
122 /* Start root node. */
123 StartChild("/");
124 }
125
Andrew Scullae9962e2019-10-03 16:51:16 +0100126 std::vector<char> Build(bool dump = false)
David Brazdil52256ff2019-08-23 15:15:15 +0100127 {
David Brazdil0dbb41f2019-09-09 18:03:35 +0100128 const char *program = "./build/image/dtc.py";
129 const char *dtc_args[] = {program, "compile", NULL};
David Brazdil52256ff2019-08-23 15:15:15 +0100130 std::vector<char> dtc_stdout;
131
132 /* Finish root node. */
133 EndChild();
134
Andrew Scullae9962e2019-10-03 16:51:16 +0100135 if (dump) {
136 Dump();
137 }
138
David Brazdil0dbb41f2019-09-09 18:03:35 +0100139 exec(program, dtc_args, dts_.str(), &dtc_stdout);
David Brazdil52256ff2019-08-23 15:15:15 +0100140 return dtc_stdout;
141 }
142
Andrew Scullae9962e2019-10-03 16:51:16 +0100143 void Dump()
144 {
145 std::cerr << dts_.str() << std::endl;
146 }
147
David Brazdil52256ff2019-08-23 15:15:15 +0100148 ManifestDtBuilder &StartChild(const std::string_view &name)
149 {
150 dts_ << name << " {" << std::endl;
151 return *this;
152 }
153
154 ManifestDtBuilder &EndChild()
155 {
156 dts_ << "};" << std::endl;
157 return *this;
158 }
159
David Brazdil74e9c3b2019-08-28 11:09:08 +0100160 ManifestDtBuilder &Compatible(const std::vector<std::string_view>
161 &value = {"hafnium,hafnium"})
162 {
163 return StringListProperty("compatible", value);
164 }
165
David Brazdil52256ff2019-08-23 15:15:15 +0100166 ManifestDtBuilder &DebugName(const std::string_view &value)
167 {
168 return StringProperty("debug_name", value);
169 }
170
171 ManifestDtBuilder &KernelFilename(const std::string_view &value)
172 {
173 return StringProperty("kernel_filename", value);
174 }
175
David Brazdile6f83222019-09-23 14:47:37 +0100176 ManifestDtBuilder &RamdiskFilename(const std::string_view &value)
177 {
178 return StringProperty("ramdisk_filename", value);
179 }
180
David Brazdil080ee312020-02-25 15:30:30 -0800181 ManifestDtBuilder &BootAddress(uint64_t value)
182 {
183 return Integer64Property("boot_address", value);
184 }
185
Andrew Scullae9962e2019-10-03 16:51:16 +0100186 ManifestDtBuilder &VcpuCount(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100187 {
188 return IntegerProperty("vcpu_count", value);
189 }
190
Andrew Scullae9962e2019-10-03 16:51:16 +0100191 ManifestDtBuilder &MemSize(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100192 {
193 return IntegerProperty("mem_size", value);
194 }
195
Andrew Scullae9962e2019-10-03 16:51:16 +0100196 ManifestDtBuilder &SmcWhitelist(const std::vector<uint32_t> &value)
197 {
198 return IntegerListProperty("smc_whitelist", value);
199 }
200
201 ManifestDtBuilder &SmcWhitelistPermissive()
202 {
203 return BooleanProperty("smc_whitelist_permissive");
204 }
205
Olivier Deprez62d99e32020-01-09 15:58:07 +0100206 ManifestDtBuilder &LoadAddress(uint64_t value)
207 {
208 return Integer64Property("load_address", value);
209 }
210
211 ManifestDtBuilder &FfaPartition()
212 {
213 return BooleanProperty("is_ffa_partition");
214 }
215
Andrew Scullae9962e2019-10-03 16:51:16 +0100216 ManifestDtBuilder &Property(const std::string_view &name,
217 const std::string_view &value)
218 {
219 dts_ << name << " = " << value << ";" << std::endl;
220 return *this;
221 }
222
David Brazdil52256ff2019-08-23 15:15:15 +0100223 private:
224 ManifestDtBuilder &StringProperty(const std::string_view &name,
225 const std::string_view &value)
226 {
227 dts_ << name << " = \"" << value << "\";" << std::endl;
228 return *this;
229 }
230
David Brazdil74e9c3b2019-08-28 11:09:08 +0100231 ManifestDtBuilder &StringListProperty(
232 const std::string_view &name,
233 const std::vector<std::string_view> &value)
234 {
235 bool is_first = true;
236
237 dts_ << name << " = ";
238 for (const std::string_view &entry : value) {
239 if (is_first) {
240 is_first = false;
241 } else {
242 dts_ << ", ";
243 }
244 dts_ << "\"" << entry << "\"";
245 }
246 dts_ << ";" << std::endl;
247 return *this;
248 }
249
David Brazdil52256ff2019-08-23 15:15:15 +0100250 ManifestDtBuilder &IntegerProperty(const std::string_view &name,
Andrew Scullae9962e2019-10-03 16:51:16 +0100251 uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100252 {
253 dts_ << name << " = <" << value << ">;" << std::endl;
254 return *this;
255 }
256
David Brazdil080ee312020-02-25 15:30:30 -0800257 ManifestDtBuilder &Integer64Property(const std::string_view &name,
258 uint64_t value)
259 {
260 uint32_t high = value >> 32;
261 uint32_t low = (uint32_t)value;
262 dts_ << name << " = <" << high << " " << low << ">;"
263 << std::endl;
264 return *this;
265 }
266
Andrew Scullae9962e2019-10-03 16:51:16 +0100267 ManifestDtBuilder &IntegerListProperty(
268 const std::string_view &name,
269 const std::vector<uint32_t> &value)
270 {
271 dts_ << name << " = < ";
272 for (const uint32_t entry : value) {
273 dts_ << entry << " ";
274 }
275 dts_ << ">;" << std::endl;
276 return *this;
277 }
278
279 ManifestDtBuilder &BooleanProperty(const std::string_view &name)
280 {
Andrew Scull5dc089e2019-11-04 13:21:03 +0000281 dts_ << name << ";" << std::endl;
282 return *this;
Andrew Scullae9962e2019-10-03 16:51:16 +0100283 }
284
David Brazdil52256ff2019-08-23 15:15:15 +0100285 std::stringstream dts_;
286};
287
David Brazdila2358d42020-01-27 18:51:38 +0000288static enum manifest_return_code manifest_from_vec(struct manifest *m,
289 const std::vector<char> &vec)
David Brazdil0dbb41f2019-09-09 18:03:35 +0100290{
David Brazdila2358d42020-01-27 18:51:38 +0000291 struct memiter it;
Olivier Deprez62d99e32020-01-09 15:58:07 +0100292 struct mpool ppool;
293 struct mm_stage1_locked mm_stage1_locked;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100294
David Brazdila2358d42020-01-27 18:51:38 +0000295 memiter_init(&it, vec.data(), vec.size());
Olivier Deprez62d99e32020-01-09 15:58:07 +0100296 return manifest_init(mm_stage1_locked, m, &it, &ppool);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100297}
298
David Brazdil52256ff2019-08-23 15:15:15 +0100299TEST(manifest, no_hypervisor_node)
David Brazdil7a462ec2019-08-15 12:27:47 +0100300{
301 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100302 std::vector<char> dtb = ManifestDtBuilder().Build();
David Brazdil7a462ec2019-08-15 12:27:47 +0100303
David Brazdila2358d42020-01-27 18:51:38 +0000304 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil7a462ec2019-08-15 12:27:47 +0100305 MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
306}
307
David Brazdil74e9c3b2019-08-28 11:09:08 +0100308TEST(manifest, no_compatible_property)
David Brazdil7a462ec2019-08-15 12:27:47 +0100309{
310 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100311
David Brazdil52256ff2019-08-23 15:15:15 +0100312 /* clang-format off */
313 std::vector<char> dtb = ManifestDtBuilder()
314 .StartChild("hypervisor")
315 .EndChild()
316 .Build();
317 /* clang-format on */
318
David Brazdilf4925382020-03-25 13:33:51 +0000319 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil7a462ec2019-08-15 12:27:47 +0100320}
321
David Brazdil74e9c3b2019-08-28 11:09:08 +0100322TEST(manifest, not_compatible)
David Brazdil7a462ec2019-08-15 12:27:47 +0100323{
324 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100325
David Brazdil52256ff2019-08-23 15:15:15 +0100326 /* clang-format off */
327 std::vector<char> dtb = ManifestDtBuilder()
328 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100329 .Compatible({ "foo,bar" })
330 .EndChild()
331 .Build();
332 /* clang-format on */
333
David Brazdila2358d42020-01-27 18:51:38 +0000334 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100335}
336
337TEST(manifest, compatible_one_of_many)
338{
339 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100340
341 /* clang-format off */
342 std::vector<char> dtb = ManifestDtBuilder()
343 .StartChild("hypervisor")
344 .Compatible({ "foo,bar", "hafnium,hafnium" })
345 .StartChild("vm1")
346 .DebugName("primary")
347 .EndChild()
348 .EndChild()
349 .Build();
350 /* clang-format on */
351
David Brazdila2358d42020-01-27 18:51:38 +0000352 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100353}
354
355TEST(manifest, no_vm_nodes)
356{
357 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100358
359 /* clang-format off */
360 std::vector<char> dtb = ManifestDtBuilder()
361 .StartChild("hypervisor")
362 .Compatible()
363 .EndChild()
364 .Build();
365 /* clang-format on */
366
David Brazdila2358d42020-01-27 18:51:38 +0000367 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NO_PRIMARY_VM);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100368}
369
370static std::vector<char> gen_long_string_dtb(bool valid)
371{
372 const char last_valid[] = "1234567890123456789012345678901";
373 const char first_invalid[] = "12345678901234567890123456789012";
David Brazdil136f2942019-09-23 14:11:03 +0100374 static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
375 static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100376
377 /* clang-format off */
378 return ManifestDtBuilder()
379 .StartChild("hypervisor")
380 .Compatible()
381 .StartChild("vm1")
382 .DebugName(valid ? last_valid : first_invalid)
383 .EndChild()
384 .EndChild()
385 .Build();
386 /* clang-format on */
387}
388
389TEST(manifest, long_string)
390{
391 struct manifest m;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100392 std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
393 std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
394
David Brazdila2358d42020-01-27 18:51:38 +0000395 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
396 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
397 MANIFEST_ERROR_STRING_TOO_LONG);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100398}
399
400TEST(manifest, reserved_vm_id)
401{
402 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100403
404 /* clang-format off */
405 std::vector<char> dtb = ManifestDtBuilder()
406 .StartChild("hypervisor")
407 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100408 .StartChild("vm1")
409 .DebugName("primary_vm")
410 .EndChild()
411 .StartChild("vm0")
412 .DebugName("reserved_vm")
413 .VcpuCount(1)
414 .MemSize(0x1000)
415 .KernelFilename("kernel")
416 .EndChild()
417 .EndChild()
418 .Build();
419 /* clang-format on */
420
David Brazdila2358d42020-01-27 18:51:38 +0000421 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_RESERVED_VM_ID);
David Brazdil7a462ec2019-08-15 12:27:47 +0100422}
423
Andrew Scullae9962e2019-10-03 16:51:16 +0100424static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
David Brazdil52256ff2019-08-23 15:15:15 +0100425{
426 /* clang-format off */
427 return ManifestDtBuilder()
428 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100429 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100430 .StartChild("vm1")
431 .DebugName("primary_vm")
432 .EndChild()
433 .StartChild("vm2")
434 .DebugName("secondary_vm")
435 .VcpuCount(vcpu_count)
436 .MemSize(0x1000)
437 .KernelFilename("kernel")
438 .EndChild()
439 .EndChild()
440 .Build();
441 /* clang-format on */
442}
David Brazdil7a462ec2019-08-15 12:27:47 +0100443
444TEST(manifest, vcpu_count_limit)
445{
446 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100447 std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
448 std::vector<char> dtb_first_invalid =
449 gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
David Brazdil7a462ec2019-08-15 12:27:47 +0100450
David Brazdila2358d42020-01-27 18:51:38 +0000451 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100452 ASSERT_EQ(m.vm_count, 2);
David Brazdil7a462ec2019-08-15 12:27:47 +0100453 ASSERT_EQ(m.vm[1].secondary.vcpu_count, UINT16_MAX);
454
David Brazdila2358d42020-01-27 18:51:38 +0000455 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100456 MANIFEST_ERROR_INTEGER_OVERFLOW);
David Brazdil7a462ec2019-08-15 12:27:47 +0100457}
458
David Brazdile6f83222019-09-23 14:47:37 +0100459TEST(manifest, no_ramdisk_primary)
460{
461 struct manifest m;
David Brazdile6f83222019-09-23 14:47:37 +0100462
463 /* clang-format off */
464 std::vector<char> dtb = ManifestDtBuilder()
465 .StartChild("hypervisor")
466 .Compatible()
467 .StartChild("vm1")
468 .DebugName("primary_vm")
469 .EndChild()
470 .EndChild()
471 .Build();
472 /* clang-format on */
473
David Brazdila2358d42020-01-27 18:51:38 +0000474 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdile6f83222019-09-23 14:47:37 +0100475 ASSERT_EQ(m.vm_count, 1);
476 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
477 ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
478}
479
David Brazdil080ee312020-02-25 15:30:30 -0800480TEST(manifest, no_boot_address_primary)
481{
482 struct manifest m;
483
484 /* clang-format off */
485 std::vector<char> dtb = ManifestDtBuilder()
486 .StartChild("hypervisor")
487 .Compatible()
488 .StartChild("vm1")
489 .DebugName("primary_vm")
490 .EndChild()
491 .EndChild()
492 .Build();
493 /* clang-format on */
494
495 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
496 ASSERT_EQ(m.vm_count, 1);
497 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
498 ASSERT_EQ(m.vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
499}
500
501TEST(manifest, boot_address_primary)
502{
503 struct manifest m;
504 const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
505
506 /* clang-format off */
507 std::vector<char> dtb = ManifestDtBuilder()
508 .StartChild("hypervisor")
509 .Compatible()
510 .StartChild("vm1")
511 .DebugName("primary_vm")
512 .BootAddress(addr)
513 .EndChild()
514 .EndChild()
515 .Build();
516 /* clang-format on */
517
518 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
519 ASSERT_EQ(m.vm_count, 1);
520 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
521 ASSERT_EQ(m.vm[0].primary.boot_address, addr);
522}
523
Andrew Scullb2c3a242019-11-04 13:52:36 +0000524static std::vector<char> gen_malformed_boolean_dtb(
525 const std::string_view &value)
Andrew Scullae9962e2019-10-03 16:51:16 +0100526{
Andrew Scullae9962e2019-10-03 16:51:16 +0100527 /* clang-format off */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000528 return ManifestDtBuilder()
Andrew Scullae9962e2019-10-03 16:51:16 +0100529 .StartChild("hypervisor")
530 .Compatible()
531 .StartChild("vm1")
532 .DebugName("primary_vm")
Andrew Scullb2c3a242019-11-04 13:52:36 +0000533 .Property("smc_whitelist_permissive", value)
Andrew Scull5dc089e2019-11-04 13:21:03 +0000534 .EndChild()
Andrew Scullae9962e2019-10-03 16:51:16 +0100535 .EndChild()
536 .Build();
537 /* clang-format on */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000538}
Andrew Scullae9962e2019-10-03 16:51:16 +0100539
Andrew Scullb2c3a242019-11-04 13:52:36 +0000540TEST(manifest, malformed_booleans)
541{
542 struct manifest m;
Andrew Scullae9962e2019-10-03 16:51:16 +0100543
Andrew Scullb2c3a242019-11-04 13:52:36 +0000544 std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
545 std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
546 std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
547 std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
Andrew Scullae9962e2019-10-03 16:51:16 +0100548
David Brazdila2358d42020-01-27 18:51:38 +0000549 ASSERT_EQ(manifest_from_vec(&m, dtb_false),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000550 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000551 ASSERT_EQ(manifest_from_vec(&m, dtb_true),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000552 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000553 ASSERT_EQ(manifest_from_vec(&m, dtb_0),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000554 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000555 ASSERT_EQ(manifest_from_vec(&m, dtb_1),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000556 MANIFEST_ERROR_MALFORMED_BOOLEAN);
Andrew Scullae9962e2019-10-03 16:51:16 +0100557}
558
David Brazdil7a462ec2019-08-15 12:27:47 +0100559TEST(manifest, valid)
560{
561 struct manifest m;
562 struct manifest_vm *vm;
David Brazdil7a462ec2019-08-15 12:27:47 +0100563
David Brazdil52256ff2019-08-23 15:15:15 +0100564 /* clang-format off */
565 std::vector<char> dtb = ManifestDtBuilder()
566 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100567 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100568 .StartChild("vm1")
569 .DebugName("primary_vm")
Andrew Scull72b43c02019-09-18 13:53:45 +0100570 .KernelFilename("primary_kernel")
David Brazdile6f83222019-09-23 14:47:37 +0100571 .RamdiskFilename("primary_ramdisk")
Andrew Scullae9962e2019-10-03 16:51:16 +0100572 .SmcWhitelist({0x32000000, 0x33001111})
David Brazdil52256ff2019-08-23 15:15:15 +0100573 .EndChild()
574 .StartChild("vm3")
575 .DebugName("second_secondary_vm")
576 .VcpuCount(43)
577 .MemSize(0x12345)
Andrew Scull72b43c02019-09-18 13:53:45 +0100578 .KernelFilename("second_secondary_kernel")
David Brazdil52256ff2019-08-23 15:15:15 +0100579 .EndChild()
580 .StartChild("vm2")
581 .DebugName("first_secondary_vm")
582 .VcpuCount(42)
583 .MemSize(12345)
Andrew Scullae9962e2019-10-03 16:51:16 +0100584 .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
585 .SmcWhitelistPermissive()
David Brazdil52256ff2019-08-23 15:15:15 +0100586 .EndChild()
587 .EndChild()
588 .Build();
589 /* clang-format on */
590
David Brazdila2358d42020-01-27 18:51:38 +0000591 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100592 ASSERT_EQ(m.vm_count, 3);
David Brazdil7a462ec2019-08-15 12:27:47 +0100593
594 vm = &m.vm[0];
David Brazdil136f2942019-09-23 14:11:03 +0100595 ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
596 ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
David Brazdile6f83222019-09-23 14:47:37 +0100597 ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
598 "primary_ramdisk");
Andrew Scullae9962e2019-10-03 16:51:16 +0100599 ASSERT_THAT(
600 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
601 ElementsAre(0x32000000, 0x33001111));
602 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100603
604 vm = &m.vm[1];
David Brazdil136f2942019-09-23 14:11:03 +0100605 ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
606 ASSERT_STREQ(string_data(&vm->kernel_filename), "");
David Brazdil7a462ec2019-08-15 12:27:47 +0100607 ASSERT_EQ(vm->secondary.vcpu_count, 42);
608 ASSERT_EQ(vm->secondary.mem_size, 12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100609 ASSERT_THAT(
610 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
611 ElementsAre(0x04000000, 0x30002222, 0x31445566));
612 ASSERT_TRUE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100613
614 vm = &m.vm[2];
David Brazdil136f2942019-09-23 14:11:03 +0100615 ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
616 ASSERT_STREQ(string_data(&vm->kernel_filename),
617 "second_secondary_kernel");
David Brazdil7a462ec2019-08-15 12:27:47 +0100618 ASSERT_EQ(vm->secondary.vcpu_count, 43);
619 ASSERT_EQ(vm->secondary.mem_size, 0x12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100620 ASSERT_THAT(
621 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
622 IsEmpty());
623 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100624}
625
Olivier Deprez62d99e32020-01-09 15:58:07 +0100626/**
627 * Class for programatically building a Partition package.
628 */
629class Partition_package
630{
631 public:
632 __attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
633 char manifest_dtb[PAGE_SIZE] = {};
634
635 Partition_package(const std::vector<char> &vec)
636 {
637 // Initialise header field
638 spkg.magic = SP_PKG_HEADER_MAGIC;
639 spkg.version = SP_PKG_HEADER_VERSION;
640 spkg.pm_offset = sizeof(struct sp_pkg_header);
641 spkg.pm_size = vec.size();
642
643 // Copy dtb into package
644 std::copy(vec.begin(), vec.end(), manifest_dtb);
645 }
646};
647
648static enum manifest_return_code ffa_manifest_from_vec(
649 struct manifest *m, const std::vector<char> &vec)
650{
651 struct memiter it;
652 struct mpool ppool;
653 struct mm_stage1_locked mm_stage1_locked;
654
655 Partition_package spkg(vec);
656
657 /* clang-format off */
658 std::vector<char> core_dtb = ManifestDtBuilder()
659 .StartChild("hypervisor")
660 .Compatible()
661 .StartChild("vm1")
662 .DebugName("primary_vm")
663 .FfaPartition()
664 .LoadAddress((uint64_t)&spkg)
665 .EndChild()
666 .EndChild()
667 .Build();
668 /* clang-format on */
669
670 memiter_init(&it, core_dtb.data(), core_dtb.size());
671 return manifest_init(mm_stage1_locked, m, &it, &ppool);
672}
673
674TEST(manifest, ffa_not_compatible)
675{
676 struct manifest m;
677
678 /* clang-format off */
679 std::vector<char> dtb = ManifestDtBuilder()
680 .Compatible({ "arm,ffa-manifest-2.0" })
681 .Property("ffa-version", "<0x10000>")
682 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
683 .Property("execution-ctx-count", "<1>")
684 .Property("exception-level", "<2>")
685 .Property("execution-state", "<0>")
686 .Property("load-address", "<0x7000000>")
687 .Property("entrypoint-offset", "<0x00001000>")
688 .Property("xlat-granule", "<0>")
689 .Property("messaging-method", "<1>")
690 .Build();
691 /* clang-format on */
692
693 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
694 MANIFEST_ERROR_NOT_COMPATIBLE);
695}
696
697TEST(manifest, ffa_missing_property)
698{
699 struct manifest m;
700
701 /* clang-format off */
702 std::vector<char> dtb = ManifestDtBuilder()
703 .Compatible({ "arm,ffa-manifest-1.0" })
704 .Property("ffa-version", "<0x10000>")
705 .Build();
706 /* clang-format on */
707
708 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
709 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
710}
711
712TEST(manifest, ffa_validate_sanity_check)
713{
714 struct manifest m;
715
716 /* Incompatible version */
717 /* clang-format off */
718 std::vector<char> dtb = ManifestDtBuilder()
719 .Compatible({ "arm,ffa-manifest-1.0" })
720 .Property("ffa-version", "<0xa1>")
721 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
722 .Property("execution-ctx-count", "<1>")
723 .Property("exception-level", "<2>")
724 .Property("execution-state", "<0>")
725 .Property("load-address", "<0x7000000>")
726 .Property("entrypoint-offset", "<0x00001000>")
727 .Property("xlat-granule", "<0>")
728 .Property("messaging-method", "<1>")
729 .Build();
730 /* clang-format on */
731 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
732 MANIFEST_ERROR_NOT_COMPATIBLE);
733
734 /* Incompatible translation granule */
735 /* clang-format off */
736 dtb = ManifestDtBuilder()
737 .Compatible({ "arm,ffa-manifest-1.0" })
738 .Property("ffa-version", "<0x10000>")
739 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
740 .Property("execution-ctx-count", "<1>")
741 .Property("exception-level", "<2>")
742 .Property("execution-state", "<0>")
743 .Property("load-address", "<0x7000000>")
744 .Property("entrypoint-offset", "<0x00001000>")
745 .Property("xlat-granule", "<3>")
746 .Property("messaging-method", "<1>")
747 .Build();
748 /* clang-format on */
749 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
750 MANIFEST_ERROR_NOT_COMPATIBLE);
751
752 /* Incompatible exeption level */
753 /* clang-format off */
754 dtb = ManifestDtBuilder()
755 .Compatible({ "arm,ffa-manifest-1.0" })
756 .Property("ffa-version", "<0x10000>")
757 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
758 .Property("execution-ctx-count", "<1>")
759 .Property("exception-level", "<6>")
760 .Property("execution-state", "<0>")
761 .Property("load-address", "<0x7000000>")
762 .Property("entrypoint-offset", "<0x00001000>")
763 .Property("xlat-granule", "<0>")
764 .Property("messaging-method", "<1>")
765 .Build();
766 /* clang-format on */
767 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
768 MANIFEST_ERROR_NOT_COMPATIBLE);
769
770 /* Incompatible execution state */
771 /* clang-format off */
772 dtb = ManifestDtBuilder()
773 .Compatible({ "arm,ffa-manifest-1.0" })
774 .Property("ffa-version", "<0x10000>")
775 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
776 .Property("execution-ctx-count", "<1>")
777 .Property("exception-level", "<2>")
778 .Property("execution-state", "<2>")
779 .Property("load-address", "<0x7000000>")
780 .Property("entrypoint-offset", "<0x00001000>")
781 .Property("xlat-granule", "<0>")
782 .Property("messaging-method", "<1>")
783 .Build();
784 /* clang-format on */
785 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
786 MANIFEST_ERROR_NOT_COMPATIBLE);
787
788 /* Incompatible messaging method */
789 /* clang-format off */
790 dtb = ManifestDtBuilder()
791 .Compatible({ "arm,ffa-manifest-1.0" })
792 .Property("ffa-version", "<0x10000>")
793 .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
794 .Property("execution-ctx-count", "<1>")
795 .Property("exception-level", "<2>")
796 .Property("execution-state", "<0>")
797 .Property("load-address", "<0x7000000>")
798 .Property("entrypoint-offset", "<0x00001000>")
799 .Property("xlat-granule", "<0>")
800 .Property("messaging-method", "<3>")
801 .Build();
802 /* clang-format on */
803 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
804 MANIFEST_ERROR_NOT_COMPATIBLE);
805}
806
807TEST(manifest, ffa_valid)
808{
809 struct manifest m;
810
811 /* clang-format off */
812 std::vector<char> 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>")
819 .Property("load-address", "<0x7000000>")
820 .Property("entrypoint-offset", "<0x00001000>")
821 .Property("xlat-granule", "<0>")
822 .Property("messaging-method", "<1>")
823 .Build();
824 /* clang-format on */
825
826 ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
827
828 ASSERT_EQ(m.vm[0].sp.ffa_version, 0x10000);
829 ASSERT_THAT(
830 std::span(m.vm[0].sp.uuid, 4),
831 ElementsAre(0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb));
832 ASSERT_EQ(m.vm[0].sp.execution_ctx_count, 1);
833 ASSERT_EQ(m.vm[0].sp.run_time_el, S_EL1);
834 ASSERT_EQ(m.vm[0].sp.execution_state, AARCH64);
835 ASSERT_EQ(m.vm[0].sp.load_addr, 0x7000000);
836 ASSERT_EQ(m.vm[0].sp.ep_offset, 0x00001000);
837 ASSERT_EQ(m.vm[0].sp.xlat_granule, PAGE_4KB);
838 ASSERT_EQ(m.vm[0].sp.messaging_method, INDIRECT_MESSAGING);
839}
840
David Brazdil7a462ec2019-08-15 12:27:47 +0100841} /* namespace */