blob: 8273ae41f769623b3bbed87f7a4d01bba3f1d666 [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
206 ManifestDtBuilder &Property(const std::string_view &name,
207 const std::string_view &value)
208 {
209 dts_ << name << " = " << value << ";" << std::endl;
210 return *this;
211 }
212
David Brazdil52256ff2019-08-23 15:15:15 +0100213 private:
214 ManifestDtBuilder &StringProperty(const std::string_view &name,
215 const std::string_view &value)
216 {
217 dts_ << name << " = \"" << value << "\";" << std::endl;
218 return *this;
219 }
220
David Brazdil74e9c3b2019-08-28 11:09:08 +0100221 ManifestDtBuilder &StringListProperty(
222 const std::string_view &name,
223 const std::vector<std::string_view> &value)
224 {
225 bool is_first = true;
226
227 dts_ << name << " = ";
228 for (const std::string_view &entry : value) {
229 if (is_first) {
230 is_first = false;
231 } else {
232 dts_ << ", ";
233 }
234 dts_ << "\"" << entry << "\"";
235 }
236 dts_ << ";" << std::endl;
237 return *this;
238 }
239
David Brazdil52256ff2019-08-23 15:15:15 +0100240 ManifestDtBuilder &IntegerProperty(const std::string_view &name,
Andrew Scullae9962e2019-10-03 16:51:16 +0100241 uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100242 {
243 dts_ << name << " = <" << value << ">;" << std::endl;
244 return *this;
245 }
246
David Brazdil080ee312020-02-25 15:30:30 -0800247 ManifestDtBuilder &Integer64Property(const std::string_view &name,
248 uint64_t value)
249 {
250 uint32_t high = value >> 32;
251 uint32_t low = (uint32_t)value;
252 dts_ << name << " = <" << high << " " << low << ">;"
253 << std::endl;
254 return *this;
255 }
256
Andrew Scullae9962e2019-10-03 16:51:16 +0100257 ManifestDtBuilder &IntegerListProperty(
258 const std::string_view &name,
259 const std::vector<uint32_t> &value)
260 {
261 dts_ << name << " = < ";
262 for (const uint32_t entry : value) {
263 dts_ << entry << " ";
264 }
265 dts_ << ">;" << std::endl;
266 return *this;
267 }
268
269 ManifestDtBuilder &BooleanProperty(const std::string_view &name)
270 {
Andrew Scull5dc089e2019-11-04 13:21:03 +0000271 dts_ << name << ";" << std::endl;
272 return *this;
Andrew Scullae9962e2019-10-03 16:51:16 +0100273 }
274
David Brazdil52256ff2019-08-23 15:15:15 +0100275 std::stringstream dts_;
276};
277
David Brazdila2358d42020-01-27 18:51:38 +0000278static enum manifest_return_code manifest_from_vec(struct manifest *m,
279 const std::vector<char> &vec)
David Brazdil0dbb41f2019-09-09 18:03:35 +0100280{
David Brazdila2358d42020-01-27 18:51:38 +0000281 struct memiter it;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100282
David Brazdila2358d42020-01-27 18:51:38 +0000283 memiter_init(&it, vec.data(), vec.size());
284 return manifest_init(m, &it);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100285}
286
David Brazdil52256ff2019-08-23 15:15:15 +0100287TEST(manifest, no_hypervisor_node)
David Brazdil7a462ec2019-08-15 12:27:47 +0100288{
289 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100290 std::vector<char> dtb = ManifestDtBuilder().Build();
David Brazdil7a462ec2019-08-15 12:27:47 +0100291
David Brazdila2358d42020-01-27 18:51:38 +0000292 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil7a462ec2019-08-15 12:27:47 +0100293 MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
294}
295
David Brazdil74e9c3b2019-08-28 11:09:08 +0100296TEST(manifest, no_compatible_property)
David Brazdil7a462ec2019-08-15 12:27:47 +0100297{
298 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100299
David Brazdil52256ff2019-08-23 15:15:15 +0100300 /* clang-format off */
301 std::vector<char> dtb = ManifestDtBuilder()
302 .StartChild("hypervisor")
303 .EndChild()
304 .Build();
305 /* clang-format on */
306
David Brazdila2358d42020-01-27 18:51:38 +0000307 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100308 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
David Brazdil7a462ec2019-08-15 12:27:47 +0100309}
310
David Brazdil74e9c3b2019-08-28 11:09:08 +0100311TEST(manifest, not_compatible)
David Brazdil7a462ec2019-08-15 12:27:47 +0100312{
313 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100314
David Brazdil52256ff2019-08-23 15:15:15 +0100315 /* clang-format off */
316 std::vector<char> dtb = ManifestDtBuilder()
317 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100318 .Compatible({ "foo,bar" })
319 .EndChild()
320 .Build();
321 /* clang-format on */
322
David Brazdila2358d42020-01-27 18:51:38 +0000323 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100324}
325
326TEST(manifest, compatible_one_of_many)
327{
328 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100329
330 /* clang-format off */
331 std::vector<char> dtb = ManifestDtBuilder()
332 .StartChild("hypervisor")
333 .Compatible({ "foo,bar", "hafnium,hafnium" })
334 .StartChild("vm1")
335 .DebugName("primary")
336 .EndChild()
337 .EndChild()
338 .Build();
339 /* clang-format on */
340
David Brazdila2358d42020-01-27 18:51:38 +0000341 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100342}
343
344TEST(manifest, no_vm_nodes)
345{
346 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100347
348 /* clang-format off */
349 std::vector<char> dtb = ManifestDtBuilder()
350 .StartChild("hypervisor")
351 .Compatible()
352 .EndChild()
353 .Build();
354 /* clang-format on */
355
David Brazdila2358d42020-01-27 18:51:38 +0000356 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NO_PRIMARY_VM);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100357}
358
359static std::vector<char> gen_long_string_dtb(bool valid)
360{
361 const char last_valid[] = "1234567890123456789012345678901";
362 const char first_invalid[] = "12345678901234567890123456789012";
David Brazdil136f2942019-09-23 14:11:03 +0100363 static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
364 static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100365
366 /* clang-format off */
367 return ManifestDtBuilder()
368 .StartChild("hypervisor")
369 .Compatible()
370 .StartChild("vm1")
371 .DebugName(valid ? last_valid : first_invalid)
372 .EndChild()
373 .EndChild()
374 .Build();
375 /* clang-format on */
376}
377
378TEST(manifest, long_string)
379{
380 struct manifest m;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100381 std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
382 std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
383
David Brazdila2358d42020-01-27 18:51:38 +0000384 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
385 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
386 MANIFEST_ERROR_STRING_TOO_LONG);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100387}
388
389TEST(manifest, reserved_vm_id)
390{
391 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100392
393 /* clang-format off */
394 std::vector<char> dtb = ManifestDtBuilder()
395 .StartChild("hypervisor")
396 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100397 .StartChild("vm1")
398 .DebugName("primary_vm")
399 .EndChild()
400 .StartChild("vm0")
401 .DebugName("reserved_vm")
402 .VcpuCount(1)
403 .MemSize(0x1000)
404 .KernelFilename("kernel")
405 .EndChild()
406 .EndChild()
407 .Build();
408 /* clang-format on */
409
David Brazdila2358d42020-01-27 18:51:38 +0000410 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_RESERVED_VM_ID);
David Brazdil7a462ec2019-08-15 12:27:47 +0100411}
412
Andrew Scullae9962e2019-10-03 16:51:16 +0100413static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
David Brazdil52256ff2019-08-23 15:15:15 +0100414{
415 /* clang-format off */
416 return ManifestDtBuilder()
417 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100418 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100419 .StartChild("vm1")
420 .DebugName("primary_vm")
421 .EndChild()
422 .StartChild("vm2")
423 .DebugName("secondary_vm")
424 .VcpuCount(vcpu_count)
425 .MemSize(0x1000)
426 .KernelFilename("kernel")
427 .EndChild()
428 .EndChild()
429 .Build();
430 /* clang-format on */
431}
David Brazdil7a462ec2019-08-15 12:27:47 +0100432
433TEST(manifest, vcpu_count_limit)
434{
435 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100436 std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
437 std::vector<char> dtb_first_invalid =
438 gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
David Brazdil7a462ec2019-08-15 12:27:47 +0100439
David Brazdila2358d42020-01-27 18:51:38 +0000440 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100441 ASSERT_EQ(m.vm_count, 2);
David Brazdil7a462ec2019-08-15 12:27:47 +0100442 ASSERT_EQ(m.vm[1].secondary.vcpu_count, UINT16_MAX);
443
David Brazdila2358d42020-01-27 18:51:38 +0000444 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100445 MANIFEST_ERROR_INTEGER_OVERFLOW);
David Brazdil7a462ec2019-08-15 12:27:47 +0100446}
447
David Brazdile6f83222019-09-23 14:47:37 +0100448TEST(manifest, no_ramdisk_primary)
449{
450 struct manifest m;
David Brazdile6f83222019-09-23 14:47:37 +0100451
452 /* clang-format off */
453 std::vector<char> dtb = ManifestDtBuilder()
454 .StartChild("hypervisor")
455 .Compatible()
456 .StartChild("vm1")
457 .DebugName("primary_vm")
458 .EndChild()
459 .EndChild()
460 .Build();
461 /* clang-format on */
462
David Brazdila2358d42020-01-27 18:51:38 +0000463 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdile6f83222019-09-23 14:47:37 +0100464 ASSERT_EQ(m.vm_count, 1);
465 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
466 ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
467}
468
David Brazdil080ee312020-02-25 15:30:30 -0800469TEST(manifest, no_boot_address_primary)
470{
471 struct manifest m;
472
473 /* clang-format off */
474 std::vector<char> dtb = ManifestDtBuilder()
475 .StartChild("hypervisor")
476 .Compatible()
477 .StartChild("vm1")
478 .DebugName("primary_vm")
479 .EndChild()
480 .EndChild()
481 .Build();
482 /* clang-format on */
483
484 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
485 ASSERT_EQ(m.vm_count, 1);
486 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
487 ASSERT_EQ(m.vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
488}
489
490TEST(manifest, boot_address_primary)
491{
492 struct manifest m;
493 const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
494
495 /* clang-format off */
496 std::vector<char> dtb = ManifestDtBuilder()
497 .StartChild("hypervisor")
498 .Compatible()
499 .StartChild("vm1")
500 .DebugName("primary_vm")
501 .BootAddress(addr)
502 .EndChild()
503 .EndChild()
504 .Build();
505 /* clang-format on */
506
507 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
508 ASSERT_EQ(m.vm_count, 1);
509 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
510 ASSERT_EQ(m.vm[0].primary.boot_address, addr);
511}
512
Andrew Scullb2c3a242019-11-04 13:52:36 +0000513static std::vector<char> gen_malformed_boolean_dtb(
514 const std::string_view &value)
Andrew Scullae9962e2019-10-03 16:51:16 +0100515{
Andrew Scullae9962e2019-10-03 16:51:16 +0100516 /* clang-format off */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000517 return ManifestDtBuilder()
Andrew Scullae9962e2019-10-03 16:51:16 +0100518 .StartChild("hypervisor")
519 .Compatible()
520 .StartChild("vm1")
521 .DebugName("primary_vm")
Andrew Scullb2c3a242019-11-04 13:52:36 +0000522 .Property("smc_whitelist_permissive", value)
Andrew Scull5dc089e2019-11-04 13:21:03 +0000523 .EndChild()
Andrew Scullae9962e2019-10-03 16:51:16 +0100524 .EndChild()
525 .Build();
526 /* clang-format on */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000527}
Andrew Scullae9962e2019-10-03 16:51:16 +0100528
Andrew Scullb2c3a242019-11-04 13:52:36 +0000529TEST(manifest, malformed_booleans)
530{
531 struct manifest m;
Andrew Scullae9962e2019-10-03 16:51:16 +0100532
Andrew Scullb2c3a242019-11-04 13:52:36 +0000533 std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
534 std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
535 std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
536 std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
Andrew Scullae9962e2019-10-03 16:51:16 +0100537
David Brazdila2358d42020-01-27 18:51:38 +0000538 ASSERT_EQ(manifest_from_vec(&m, dtb_false),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000539 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000540 ASSERT_EQ(manifest_from_vec(&m, dtb_true),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000541 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000542 ASSERT_EQ(manifest_from_vec(&m, dtb_0),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000543 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000544 ASSERT_EQ(manifest_from_vec(&m, dtb_1),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000545 MANIFEST_ERROR_MALFORMED_BOOLEAN);
Andrew Scullae9962e2019-10-03 16:51:16 +0100546}
547
David Brazdil7a462ec2019-08-15 12:27:47 +0100548TEST(manifest, valid)
549{
550 struct manifest m;
551 struct manifest_vm *vm;
David Brazdil7a462ec2019-08-15 12:27:47 +0100552
David Brazdil52256ff2019-08-23 15:15:15 +0100553 /* clang-format off */
554 std::vector<char> dtb = ManifestDtBuilder()
555 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100556 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100557 .StartChild("vm1")
558 .DebugName("primary_vm")
Andrew Scull72b43c02019-09-18 13:53:45 +0100559 .KernelFilename("primary_kernel")
David Brazdile6f83222019-09-23 14:47:37 +0100560 .RamdiskFilename("primary_ramdisk")
Andrew Scullae9962e2019-10-03 16:51:16 +0100561 .SmcWhitelist({0x32000000, 0x33001111})
David Brazdil52256ff2019-08-23 15:15:15 +0100562 .EndChild()
563 .StartChild("vm3")
564 .DebugName("second_secondary_vm")
565 .VcpuCount(43)
566 .MemSize(0x12345)
Andrew Scull72b43c02019-09-18 13:53:45 +0100567 .KernelFilename("second_secondary_kernel")
David Brazdil52256ff2019-08-23 15:15:15 +0100568 .EndChild()
569 .StartChild("vm2")
570 .DebugName("first_secondary_vm")
571 .VcpuCount(42)
572 .MemSize(12345)
Andrew Scullae9962e2019-10-03 16:51:16 +0100573 .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
574 .SmcWhitelistPermissive()
David Brazdil52256ff2019-08-23 15:15:15 +0100575 .EndChild()
576 .EndChild()
577 .Build();
578 /* clang-format on */
579
David Brazdila2358d42020-01-27 18:51:38 +0000580 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100581 ASSERT_EQ(m.vm_count, 3);
David Brazdil7a462ec2019-08-15 12:27:47 +0100582
583 vm = &m.vm[0];
David Brazdil136f2942019-09-23 14:11:03 +0100584 ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
585 ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
David Brazdile6f83222019-09-23 14:47:37 +0100586 ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
587 "primary_ramdisk");
Andrew Scullae9962e2019-10-03 16:51:16 +0100588 ASSERT_THAT(
589 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
590 ElementsAre(0x32000000, 0x33001111));
591 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100592
593 vm = &m.vm[1];
David Brazdil136f2942019-09-23 14:11:03 +0100594 ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
595 ASSERT_STREQ(string_data(&vm->kernel_filename), "");
David Brazdil7a462ec2019-08-15 12:27:47 +0100596 ASSERT_EQ(vm->secondary.vcpu_count, 42);
597 ASSERT_EQ(vm->secondary.mem_size, 12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100598 ASSERT_THAT(
599 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
600 ElementsAre(0x04000000, 0x30002222, 0x31445566));
601 ASSERT_TRUE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100602
603 vm = &m.vm[2];
David Brazdil136f2942019-09-23 14:11:03 +0100604 ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
605 ASSERT_STREQ(string_data(&vm->kernel_filename),
606 "second_secondary_kernel");
David Brazdil7a462ec2019-08-15 12:27:47 +0100607 ASSERT_EQ(vm->secondary.vcpu_count, 43);
608 ASSERT_EQ(vm->secondary.mem_size, 0x12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100609 ASSERT_THAT(
610 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
611 IsEmpty());
612 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100613}
614
615} /* namespace */