blob: 097c93ed30959ebeb65acbb66bf6a3a9650be8d2 [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
Andrew Scullae9962e2019-10-03 16:51:16 +0100181 ManifestDtBuilder &VcpuCount(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100182 {
183 return IntegerProperty("vcpu_count", value);
184 }
185
Andrew Scullae9962e2019-10-03 16:51:16 +0100186 ManifestDtBuilder &MemSize(uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100187 {
188 return IntegerProperty("mem_size", value);
189 }
190
Andrew Scullae9962e2019-10-03 16:51:16 +0100191 ManifestDtBuilder &SmcWhitelist(const std::vector<uint32_t> &value)
192 {
193 return IntegerListProperty("smc_whitelist", value);
194 }
195
196 ManifestDtBuilder &SmcWhitelistPermissive()
197 {
198 return BooleanProperty("smc_whitelist_permissive");
199 }
200
201 ManifestDtBuilder &Property(const std::string_view &name,
202 const std::string_view &value)
203 {
204 dts_ << name << " = " << value << ";" << std::endl;
205 return *this;
206 }
207
David Brazdil52256ff2019-08-23 15:15:15 +0100208 private:
209 ManifestDtBuilder &StringProperty(const std::string_view &name,
210 const std::string_view &value)
211 {
212 dts_ << name << " = \"" << value << "\";" << std::endl;
213 return *this;
214 }
215
David Brazdil74e9c3b2019-08-28 11:09:08 +0100216 ManifestDtBuilder &StringListProperty(
217 const std::string_view &name,
218 const std::vector<std::string_view> &value)
219 {
220 bool is_first = true;
221
222 dts_ << name << " = ";
223 for (const std::string_view &entry : value) {
224 if (is_first) {
225 is_first = false;
226 } else {
227 dts_ << ", ";
228 }
229 dts_ << "\"" << entry << "\"";
230 }
231 dts_ << ";" << std::endl;
232 return *this;
233 }
234
David Brazdil52256ff2019-08-23 15:15:15 +0100235 ManifestDtBuilder &IntegerProperty(const std::string_view &name,
Andrew Scullae9962e2019-10-03 16:51:16 +0100236 uint32_t value)
David Brazdil52256ff2019-08-23 15:15:15 +0100237 {
238 dts_ << name << " = <" << value << ">;" << std::endl;
239 return *this;
240 }
241
Andrew Scullae9962e2019-10-03 16:51:16 +0100242 ManifestDtBuilder &IntegerListProperty(
243 const std::string_view &name,
244 const std::vector<uint32_t> &value)
245 {
246 dts_ << name << " = < ";
247 for (const uint32_t entry : value) {
248 dts_ << entry << " ";
249 }
250 dts_ << ">;" << std::endl;
251 return *this;
252 }
253
254 ManifestDtBuilder &BooleanProperty(const std::string_view &name)
255 {
Andrew Scull5dc089e2019-11-04 13:21:03 +0000256 dts_ << name << ";" << std::endl;
257 return *this;
Andrew Scullae9962e2019-10-03 16:51:16 +0100258 }
259
David Brazdil52256ff2019-08-23 15:15:15 +0100260 std::stringstream dts_;
261};
262
David Brazdila2358d42020-01-27 18:51:38 +0000263static enum manifest_return_code manifest_from_vec(struct manifest *m,
264 const std::vector<char> &vec)
David Brazdil0dbb41f2019-09-09 18:03:35 +0100265{
David Brazdila2358d42020-01-27 18:51:38 +0000266 struct memiter it;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100267
David Brazdila2358d42020-01-27 18:51:38 +0000268 memiter_init(&it, vec.data(), vec.size());
269 return manifest_init(m, &it);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100270}
271
David Brazdil52256ff2019-08-23 15:15:15 +0100272TEST(manifest, no_hypervisor_node)
David Brazdil7a462ec2019-08-15 12:27:47 +0100273{
274 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100275 std::vector<char> dtb = ManifestDtBuilder().Build();
David Brazdil7a462ec2019-08-15 12:27:47 +0100276
David Brazdila2358d42020-01-27 18:51:38 +0000277 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil7a462ec2019-08-15 12:27:47 +0100278 MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE);
279}
280
David Brazdil74e9c3b2019-08-28 11:09:08 +0100281TEST(manifest, no_compatible_property)
David Brazdil7a462ec2019-08-15 12:27:47 +0100282{
283 struct manifest m;
David Brazdil7a462ec2019-08-15 12:27:47 +0100284
David Brazdil52256ff2019-08-23 15:15:15 +0100285 /* clang-format off */
286 std::vector<char> dtb = ManifestDtBuilder()
287 .StartChild("hypervisor")
288 .EndChild()
289 .Build();
290 /* clang-format on */
291
David Brazdila2358d42020-01-27 18:51:38 +0000292 ASSERT_EQ(manifest_from_vec(&m, dtb),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100293 MANIFEST_ERROR_PROPERTY_NOT_FOUND);
David Brazdil7a462ec2019-08-15 12:27:47 +0100294}
295
David Brazdil74e9c3b2019-08-28 11:09:08 +0100296TEST(manifest, not_compatible)
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")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100303 .Compatible({ "foo,bar" })
304 .EndChild()
305 .Build();
306 /* clang-format on */
307
David Brazdila2358d42020-01-27 18:51:38 +0000308 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100309}
310
311TEST(manifest, compatible_one_of_many)
312{
313 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100314
315 /* clang-format off */
316 std::vector<char> dtb = ManifestDtBuilder()
317 .StartChild("hypervisor")
318 .Compatible({ "foo,bar", "hafnium,hafnium" })
319 .StartChild("vm1")
320 .DebugName("primary")
321 .EndChild()
322 .EndChild()
323 .Build();
324 /* clang-format on */
325
David Brazdila2358d42020-01-27 18:51:38 +0000326 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100327}
328
329TEST(manifest, no_vm_nodes)
330{
331 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100332
333 /* clang-format off */
334 std::vector<char> dtb = ManifestDtBuilder()
335 .StartChild("hypervisor")
336 .Compatible()
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_ERROR_NO_PRIMARY_VM);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100342}
343
344static std::vector<char> gen_long_string_dtb(bool valid)
345{
346 const char last_valid[] = "1234567890123456789012345678901";
347 const char first_invalid[] = "12345678901234567890123456789012";
David Brazdil136f2942019-09-23 14:11:03 +0100348 static_assert(sizeof(last_valid) == STRING_MAX_SIZE);
349 static_assert(sizeof(first_invalid) == STRING_MAX_SIZE + 1);
David Brazdil0dbb41f2019-09-09 18:03:35 +0100350
351 /* clang-format off */
352 return ManifestDtBuilder()
353 .StartChild("hypervisor")
354 .Compatible()
355 .StartChild("vm1")
356 .DebugName(valid ? last_valid : first_invalid)
357 .EndChild()
358 .EndChild()
359 .Build();
360 /* clang-format on */
361}
362
363TEST(manifest, long_string)
364{
365 struct manifest m;
David Brazdil0dbb41f2019-09-09 18:03:35 +0100366 std::vector<char> dtb_last_valid = gen_long_string_dtb(true);
367 std::vector<char> dtb_first_invalid = gen_long_string_dtb(false);
368
David Brazdila2358d42020-01-27 18:51:38 +0000369 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
370 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
371 MANIFEST_ERROR_STRING_TOO_LONG);
David Brazdil74e9c3b2019-08-28 11:09:08 +0100372}
373
374TEST(manifest, reserved_vm_id)
375{
376 struct manifest m;
David Brazdil74e9c3b2019-08-28 11:09:08 +0100377
378 /* clang-format off */
379 std::vector<char> dtb = ManifestDtBuilder()
380 .StartChild("hypervisor")
381 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100382 .StartChild("vm1")
383 .DebugName("primary_vm")
384 .EndChild()
385 .StartChild("vm0")
386 .DebugName("reserved_vm")
387 .VcpuCount(1)
388 .MemSize(0x1000)
389 .KernelFilename("kernel")
390 .EndChild()
391 .EndChild()
392 .Build();
393 /* clang-format on */
394
David Brazdila2358d42020-01-27 18:51:38 +0000395 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_RESERVED_VM_ID);
David Brazdil7a462ec2019-08-15 12:27:47 +0100396}
397
Andrew Scullae9962e2019-10-03 16:51:16 +0100398static std::vector<char> gen_vcpu_count_limit_dtb(uint32_t vcpu_count)
David Brazdil52256ff2019-08-23 15:15:15 +0100399{
400 /* clang-format off */
401 return ManifestDtBuilder()
402 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100403 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100404 .StartChild("vm1")
405 .DebugName("primary_vm")
406 .EndChild()
407 .StartChild("vm2")
408 .DebugName("secondary_vm")
409 .VcpuCount(vcpu_count)
410 .MemSize(0x1000)
411 .KernelFilename("kernel")
412 .EndChild()
413 .EndChild()
414 .Build();
415 /* clang-format on */
416}
David Brazdil7a462ec2019-08-15 12:27:47 +0100417
418TEST(manifest, vcpu_count_limit)
419{
420 struct manifest m;
David Brazdil52256ff2019-08-23 15:15:15 +0100421 std::vector<char> dtb_last_valid = gen_vcpu_count_limit_dtb(UINT16_MAX);
422 std::vector<char> dtb_first_invalid =
423 gen_vcpu_count_limit_dtb(UINT16_MAX + 1);
David Brazdil7a462ec2019-08-15 12:27:47 +0100424
David Brazdila2358d42020-01-27 18:51:38 +0000425 ASSERT_EQ(manifest_from_vec(&m, dtb_last_valid), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100426 ASSERT_EQ(m.vm_count, 2);
David Brazdil7a462ec2019-08-15 12:27:47 +0100427 ASSERT_EQ(m.vm[1].secondary.vcpu_count, UINT16_MAX);
428
David Brazdila2358d42020-01-27 18:51:38 +0000429 ASSERT_EQ(manifest_from_vec(&m, dtb_first_invalid),
David Brazdil0dbb41f2019-09-09 18:03:35 +0100430 MANIFEST_ERROR_INTEGER_OVERFLOW);
David Brazdil7a462ec2019-08-15 12:27:47 +0100431}
432
David Brazdile6f83222019-09-23 14:47:37 +0100433TEST(manifest, no_ramdisk_primary)
434{
435 struct manifest m;
David Brazdile6f83222019-09-23 14:47:37 +0100436
437 /* clang-format off */
438 std::vector<char> dtb = ManifestDtBuilder()
439 .StartChild("hypervisor")
440 .Compatible()
441 .StartChild("vm1")
442 .DebugName("primary_vm")
443 .EndChild()
444 .EndChild()
445 .Build();
446 /* clang-format on */
447
David Brazdila2358d42020-01-27 18:51:38 +0000448 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdile6f83222019-09-23 14:47:37 +0100449 ASSERT_EQ(m.vm_count, 1);
450 ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
451 ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
452}
453
Andrew Scullb2c3a242019-11-04 13:52:36 +0000454static std::vector<char> gen_malformed_boolean_dtb(
455 const std::string_view &value)
Andrew Scullae9962e2019-10-03 16:51:16 +0100456{
Andrew Scullae9962e2019-10-03 16:51:16 +0100457 /* clang-format off */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000458 return ManifestDtBuilder()
Andrew Scullae9962e2019-10-03 16:51:16 +0100459 .StartChild("hypervisor")
460 .Compatible()
461 .StartChild("vm1")
462 .DebugName("primary_vm")
Andrew Scullb2c3a242019-11-04 13:52:36 +0000463 .Property("smc_whitelist_permissive", value)
Andrew Scull5dc089e2019-11-04 13:21:03 +0000464 .EndChild()
Andrew Scullae9962e2019-10-03 16:51:16 +0100465 .EndChild()
466 .Build();
467 /* clang-format on */
Andrew Scullb2c3a242019-11-04 13:52:36 +0000468}
Andrew Scullae9962e2019-10-03 16:51:16 +0100469
Andrew Scullb2c3a242019-11-04 13:52:36 +0000470TEST(manifest, malformed_booleans)
471{
472 struct manifest m;
Andrew Scullae9962e2019-10-03 16:51:16 +0100473
Andrew Scullb2c3a242019-11-04 13:52:36 +0000474 std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
475 std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
476 std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
477 std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
Andrew Scullae9962e2019-10-03 16:51:16 +0100478
David Brazdila2358d42020-01-27 18:51:38 +0000479 ASSERT_EQ(manifest_from_vec(&m, dtb_false),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000480 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000481 ASSERT_EQ(manifest_from_vec(&m, dtb_true),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000482 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000483 ASSERT_EQ(manifest_from_vec(&m, dtb_0),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000484 MANIFEST_ERROR_MALFORMED_BOOLEAN);
David Brazdila2358d42020-01-27 18:51:38 +0000485 ASSERT_EQ(manifest_from_vec(&m, dtb_1),
Andrew Scullb2c3a242019-11-04 13:52:36 +0000486 MANIFEST_ERROR_MALFORMED_BOOLEAN);
Andrew Scullae9962e2019-10-03 16:51:16 +0100487}
488
David Brazdil7a462ec2019-08-15 12:27:47 +0100489TEST(manifest, valid)
490{
491 struct manifest m;
492 struct manifest_vm *vm;
David Brazdil7a462ec2019-08-15 12:27:47 +0100493
David Brazdil52256ff2019-08-23 15:15:15 +0100494 /* clang-format off */
495 std::vector<char> dtb = ManifestDtBuilder()
496 .StartChild("hypervisor")
David Brazdil74e9c3b2019-08-28 11:09:08 +0100497 .Compatible()
David Brazdil52256ff2019-08-23 15:15:15 +0100498 .StartChild("vm1")
499 .DebugName("primary_vm")
Andrew Scull72b43c02019-09-18 13:53:45 +0100500 .KernelFilename("primary_kernel")
David Brazdile6f83222019-09-23 14:47:37 +0100501 .RamdiskFilename("primary_ramdisk")
Andrew Scullae9962e2019-10-03 16:51:16 +0100502 .SmcWhitelist({0x32000000, 0x33001111})
David Brazdil52256ff2019-08-23 15:15:15 +0100503 .EndChild()
504 .StartChild("vm3")
505 .DebugName("second_secondary_vm")
506 .VcpuCount(43)
507 .MemSize(0x12345)
Andrew Scull72b43c02019-09-18 13:53:45 +0100508 .KernelFilename("second_secondary_kernel")
David Brazdil52256ff2019-08-23 15:15:15 +0100509 .EndChild()
510 .StartChild("vm2")
511 .DebugName("first_secondary_vm")
512 .VcpuCount(42)
513 .MemSize(12345)
Andrew Scullae9962e2019-10-03 16:51:16 +0100514 .SmcWhitelist({0x04000000, 0x30002222, 0x31445566})
515 .SmcWhitelistPermissive()
David Brazdil52256ff2019-08-23 15:15:15 +0100516 .EndChild()
517 .EndChild()
518 .Build();
519 /* clang-format on */
520
David Brazdila2358d42020-01-27 18:51:38 +0000521 ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
David Brazdil0251b942019-09-10 15:59:50 +0100522 ASSERT_EQ(m.vm_count, 3);
David Brazdil7a462ec2019-08-15 12:27:47 +0100523
524 vm = &m.vm[0];
David Brazdil136f2942019-09-23 14:11:03 +0100525 ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
526 ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
David Brazdile6f83222019-09-23 14:47:37 +0100527 ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
528 "primary_ramdisk");
Andrew Scullae9962e2019-10-03 16:51:16 +0100529 ASSERT_THAT(
530 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
531 ElementsAre(0x32000000, 0x33001111));
532 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100533
534 vm = &m.vm[1];
David Brazdil136f2942019-09-23 14:11:03 +0100535 ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");
536 ASSERT_STREQ(string_data(&vm->kernel_filename), "");
David Brazdil7a462ec2019-08-15 12:27:47 +0100537 ASSERT_EQ(vm->secondary.vcpu_count, 42);
538 ASSERT_EQ(vm->secondary.mem_size, 12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100539 ASSERT_THAT(
540 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
541 ElementsAre(0x04000000, 0x30002222, 0x31445566));
542 ASSERT_TRUE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100543
544 vm = &m.vm[2];
David Brazdil136f2942019-09-23 14:11:03 +0100545 ASSERT_STREQ(string_data(&vm->debug_name), "second_secondary_vm");
546 ASSERT_STREQ(string_data(&vm->kernel_filename),
547 "second_secondary_kernel");
David Brazdil7a462ec2019-08-15 12:27:47 +0100548 ASSERT_EQ(vm->secondary.vcpu_count, 43);
549 ASSERT_EQ(vm->secondary.mem_size, 0x12345);
Andrew Scullae9962e2019-10-03 16:51:16 +0100550 ASSERT_THAT(
551 std::span(vm->smc_whitelist.smcs, vm->smc_whitelist.smc_count),
552 IsEmpty());
553 ASSERT_FALSE(vm->smc_whitelist.permissive);
David Brazdil7a462ec2019-08-15 12:27:47 +0100554}
555
556} /* namespace */