blob: bed1675f61b8d0b0b8c89a54209357188e04f17c [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 Brazdilf4925382020-03-25 13:33:51 +0000307 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil7a462ec2019-08-15 12:27:47 +0100308}
309
David Brazdil74e9c3b2019-08-28 11:09:08 +0100310TEST(manifest, not_compatible)
David Brazdil7a462ec2019-08-15 12:27:47 +0100311{
312 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100313
David Brazdil52256ff2019-08-23 15:15:15 +0100314 /* clang-format off */
315 std::vector<char> dtb = ManifestDtBuilder()
316 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100317 .Compatible({ "foo,bar" })
318 .EndChild()
319 .Build();
320 /* clang-format on */
321
David Brazdila2358d42020-01-27 18:51:38 +0000322 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100323}
324
325TEST(manifest, compatible_one_of_many)
326{
327 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100328
329 /* clang-format off */
330 std::vector<char> dtb = ManifestDtBuilder()
331 .StartChild("hypervisor")
332 .Compatible({ "foo,bar", "hafnium,hafnium" })
333 .StartChild("vm1")
334 .DebugName("primary")
335 .EndChild()
336 .EndChild()
337 .Build();
338 /* clang-format on */
339
David Brazdila2358d42020-01-27 18:51:38 +0000340 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100341}
342
343TEST(manifest, no_vm_nodes)
344{
345 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100346
347 /* clang-format off */
348 std::vector<char> dtb = ManifestDtBuilder()
349 .StartChild("hypervisor")
350 .Compatible()
351 .EndChild()
352 .Build();
353 /* clang-format on */
354
David Brazdila2358d42020-01-27 18:51:38 +0000355 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NO_PRIMARY_VM);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100356}
357
358static std::vector<char> gen_long_string_dtb(bool valid)
359{
360 const char last_valid[] = "1234567890123456789012345678901";
361 const char first_invalid[] = "12345678901234567890123456789012";
David Brazdil136f2942019-09-23 14:11:03 +0100362 static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
363 static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100364
365 /* clang-format off */
366 return ManifestDtBuilder()
367 .StartChild("hypervisor")
368 .Compatible()
369 .StartChild("vm1")
370 .DebugName(valid ? last_valid : first_invalid)
371 .EndChild()
372 .EndChild()
373 .Build();
374 /* clang-format on */
375}
376
377TEST(manifest, long_string)
378{
379 struct manifest m;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100380 std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
381 std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
382
David Brazdila2358d42020-01-27 18:51:38 +0000383 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
384 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
385 MANIFEST_ERROR_STRING_TOO_LONG);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100386}
387
388TEST(manifest, reserved_vm_id)
389{
390 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100391
392 /* clang-format off */
393 std::vector<char> dtb = ManifestDtBuilder()
394 .StartChild("hypervisor")
395 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100396 .StartChild("vm1")
397 .DebugName("primary_vm")
398 .EndChild()
399 .StartChild("vm0")
400 .DebugName("reserved_vm")
401 .VcpuCount(1)
402 .MemSize(0x1000)
403 .KernelFilename("kernel")
404 .EndChild()
405 .EndChild()
406 .Build();
407 /* clang-format on */
408
David Brazdila2358d42020-01-27 18:51:38 +0000409 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_RESERVED_VM_ID);
David Brazdil7a462ec2019-08-15 12:27:47 +0100410}
411
Andrew Scullae9962e2019-10-03 16:51:16 +0100412static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
David Brazdil52256ff2019-08-23 15:15:15 +0100413{
414 /* clang-format off */
415 return ManifestDtBuilder()
416 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100417 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100418 .StartChild("vm1")
419 .DebugName("primary_vm")
420 .EndChild()
421 .StartChild("vm2")
422 .DebugName("secondary_vm")
423 .VcpuCount(vcpu_count)
424 .MemSize(0x1000)
425 .KernelFilename("kernel")
426 .EndChild()
427 .EndChild()
428 .Build();
429 /* clang-format on */
430}
David Brazdil7a462ec2019-08-15 12:27:47 +0100431
432TEST(manifest, vcpu_count_limit)
433{
434 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100435 std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
436 std::vector<char> dtb_first_invalid =
437 gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
David Brazdil7a462ec2019-08-15 12:27:47 +0100438
David Brazdila2358d42020-01-27 18:51:38 +0000439 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100440 ASSERT_EQ(m.vm_count, 2);
David Brazdil7a462ec2019-08-15 12:27:47 +0100441 ASSERT_EQ(m.vm[1].secondary.vcpu_count, UINT16_MAX);
442
David Brazdila2358d42020-01-27 18:51:38 +0000443 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100444 MANIFEST_ERROR_INTEGER_OVERFLOW);
David Brazdil7a462ec2019-08-15 12:27:47 +0100445}
446
David Brazdile6f83222019-09-23 14:47:37 +0100447TEST(manifest, no_ramdisk_primary)
448{
449 struct manifest m;
David Brazdile6f83222019-09-23 14:47:37 +0100450
451 /* clang-format off */
452 std::vector<char> dtb = ManifestDtBuilder()
453 .StartChild("hypervisor")
454 .Compatible()
455 .StartChild("vm1")
456 .DebugName("primary_vm")
457 .EndChild()
458 .EndChild()
459 .Build();
460 /* clang-format on */
461
David Brazdila2358d42020-01-27 18:51:38 +0000462 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdile6f83222019-09-23 14:47:37 +0100463 ASSERT_EQ(m.vm_count, 1);
464 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
465 ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
466}
467
David Brazdil080ee312020-02-25 15:30:30 -0800468TEST(manifest, no_boot_address_primary)
469{
470 struct manifest m;
471
472 /* clang-format off */
473 std::vector<char> dtb = ManifestDtBuilder()
474 .StartChild("hypervisor")
475 .Compatible()
476 .StartChild("vm1")
477 .DebugName("primary_vm")
478 .EndChild()
479 .EndChild()
480 .Build();
481 /* clang-format on */
482
483 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
484 ASSERT_EQ(m.vm_count, 1);
485 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
486 ASSERT_EQ(m.vm[0].primary.boot_address, MANIFEST_INVALID_ADDRESS);
487}
488
489TEST(manifest, boot_address_primary)
490{
491 struct manifest m;
492 const uint64_t addr = UINT64_C(0x12345678ABCDEFEF);
493
494 /* clang-format off */
495 std::vector<char> dtb = ManifestDtBuilder()
496 .StartChild("hypervisor")
497 .Compatible()
498 .StartChild("vm1")
499 .DebugName("primary_vm")
500 .BootAddress(addr)
501 .EndChild()
502 .EndChild()
503 .Build();
504 /* clang-format on */
505
506 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
507 ASSERT_EQ(m.vm_count, 1);
508 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
509 ASSERT_EQ(m.vm[0].primary.boot_address, addr);
510}
511
Andrew Scullb2c3a242019-11-04 13:52:36 +0000512static std::vector<char> gen_malformed_boolean_dtb(
513 const std::string_view &value)
Andrew Scullae9962e2019-10-03 16:51:16 +0100514{
Andrew Scullae9962e2019-10-03 16:51:16 +0100515 /* clang-format off */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000516 return ManifestDtBuilder()
Andrew Scullae9962e2019-10-03 16:51:16 +0100517 .StartChild("hypervisor")
518 .Compatible()
519 .StartChild("vm1")
520 .DebugName("primary_vm")
Andrew Scullb2c3a242019-11-04 13:52:36 +0000521 .Property("smc_whitelist_permissive", value)
Andrew Scull5dc089e2019-11-04 13:21:03 +0000522 .EndChild()
Andrew Scullae9962e2019-10-03 16:51:16 +0100523 .EndChild()
524 .Build();
525 /* clang-format on */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000526}
Andrew Scullae9962e2019-10-03 16:51:16 +0100527
Andrew Scullb2c3a242019-11-04 13:52:36 +0000528TEST(manifest, malformed_booleans)
529{
530 struct manifest m;
Andrew Scullae9962e2019-10-03 16:51:16 +0100531
Andrew Scullb2c3a242019-11-04 13:52:36 +0000532 std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
533 std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
534 std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
535 std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
Andrew Scullae9962e2019-10-03 16:51:16 +0100536
David Brazdila2358d42020-01-27 18:51:38 +0000537 ASSERT_EQ(manifest_from_vec(&m, dtb_false),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000538 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000539 ASSERT_EQ(manifest_from_vec(&m, dtb_true),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000540 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000541 ASSERT_EQ(manifest_from_vec(&m, dtb_0),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000542 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000543 ASSERT_EQ(manifest_from_vec(&m, dtb_1),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000544 MANIFEST_ERROR_MALFORMED_BOOLEAN);
Andrew Scullae9962e2019-10-03 16:51:16 +0100545}
546
David Brazdil7a462ec2019-08-15 12:27:47 +0100547TEST(manifest, valid)
548{
549 struct manifest m;
550 struct manifest_vm *vm;
David Brazdil7a462ec2019-08-15 12:27:47 +0100551
David Brazdil52256ff2019-08-23 15:15:15 +0100552 /* clang-format off */
553 std::vector<char> dtb = ManifestDtBuilder()
554 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100555 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100556 .StartChild("vm1")
557 .DebugName("primary_vm")
Andrew Scull72b43c02019-09-18 13:53:45 +0100558 .KernelFilename("primary_kernel")
David Brazdile6f83222019-09-23 14:47:37 +0100559 .RamdiskFilename("primary_ramdisk")
Andrew Scullae9962e2019-10-03 16:51:16 +0100560 .SmcWhitelist({0x32000000, 0x33001111})
David Brazdil52256ff2019-08-23 15:15:15 +0100561 .EndChild()
562 .StartChild("vm3")
563 .DebugName("second_secondary_vm")
564 .VcpuCount(43)
565 .MemSize(0x12345)
Andrew Scull72b43c02019-09-18 13:53:45 +0100566 .KernelFilename("second_secondary_kernel")
David Brazdil52256ff2019-08-23 15:15:15 +0100567 .EndChild()
568 .StartChild("vm2")
569 .DebugName("first_secondary_vm")
570 .VcpuCount(42)
571 .MemSize(12345)
Andrew Scullae9962e2019-10-03 16:51:16 +0100572 .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
573 .SmcWhitelistPermissive()
David Brazdil52256ff2019-08-23 15:15:15 +0100574 .EndChild()
575 .EndChild()
576 .Build();
577 /* clang-format on */
578
David Brazdila2358d42020-01-27 18:51:38 +0000579 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100580 ASSERT_EQ(m.vm_count, 3);
David Brazdil7a462ec2019-08-15 12:27:47 +0100581
582 vm = &m.vm[0];
David Brazdil136f2942019-09-23 14:11:03 +0100583 ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
584 ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
David Brazdile6f83222019-09-23 14:47:37 +0100585 ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
586 "primary_ramdisk");
Andrew Scullae9962e2019-10-03 16:51:16 +0100587 ASSERT_THAT(
588 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
589 ElementsAre(0x32000000, 0x33001111));
590 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100591
592 vm = &m.vm[1];
David Brazdil136f2942019-09-23 14:11:03 +0100593 ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
594 ASSERT_STREQ(string_data(&vm->kernel_filename), "");
David Brazdil7a462ec2019-08-15 12:27:47 +0100595 ASSERT_EQ(vm->secondary.vcpu_count, 42);
596 ASSERT_EQ(vm->secondary.mem_size, 12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100597 ASSERT_THAT(
598 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
599 ElementsAre(0x04000000, 0x30002222, 0x31445566));
600 ASSERT_TRUE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100601
602 vm = &m.vm[2];
David Brazdil136f2942019-09-23 14:11:03 +0100603 ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
604 ASSERT_STREQ(string_data(&vm->kernel_filename),
605 "second_secondary_kernel");
David Brazdil7a462ec2019-08-15 12:27:47 +0100606 ASSERT_EQ(vm->secondary.vcpu_count, 43);
607 ASSERT_EQ(vm->secondary.mem_size, 0x12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100608 ASSERT_THAT(
609 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
610 IsEmpty());
611 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100612}
613
614} /* namespace */