blob: e5c62a1abe8b2951a6e76cff10d595c61189a0a5 [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
17#include "hf/manifest.h"
18
19#include "hf/addr.h"
20#include "hf/check.h"
21#include "hf/fdt.h"
22#include "hf/static_assert.h"
23#include "hf/std.h"
24
25#define TRY(expr) \
26 do { \
27 enum manifest_return_code ret_code = (expr); \
28 if (ret_code != MANIFEST_SUCCESS) { \
29 return ret_code; \
30 } \
31 } while (0)
32
33#define VM_NAME_BUF_SIZE (2 + 5 + 1) /* "vm" + number + null terminator */
34static_assert(MAX_VMS <= 99999, "Insufficient VM_NAME_BUF_SIZE");
35
36/**
37 * Generates a string with the two letters "vm" followed by an integer.
38 * Assumes `buf` is of size VM_NAME_BUF_SIZE.
39 */
40static const char *generate_vm_node_name(char *buf, spci_vm_id_t vm_id)
41{
42 static const char *digits = "0123456789";
43 char *ptr = buf + VM_NAME_BUF_SIZE;
44
45 *(--ptr) = '\0';
46 do {
47 *(--ptr) = digits[vm_id % 10];
48 vm_id /= 10;
49 } while (vm_id);
50 *(--ptr) = 'm';
51 *(--ptr) = 'v';
52
53 return ptr;
54}
55
56static enum manifest_return_code read_string(const struct fdt_node *node,
57 const char *property,
58 struct memiter *out)
59{
60 const char *data;
61 uint32_t size;
62
63 if (!fdt_read_property(node, property, &data, &size)) {
64 return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
65 }
66
67 if (data[size - 1] != '\0') {
68 return MANIFEST_ERROR_MALFORMED_STRING;
69 }
70
71 memiter_init(out, data, size - 1);
72 return MANIFEST_SUCCESS;
73}
74
75static enum manifest_return_code read_uint64(const struct fdt_node *node,
76 const char *property,
77 uint64_t *out)
78{
79 const char *data;
80 uint32_t size;
81
82 if (!fdt_read_property(node, property, &data, &size)) {
83 return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
84 }
85
86 if (!fdt_parse_number(data, size, out)) {
87 return MANIFEST_ERROR_MALFORMED_INTEGER;
88 }
89
90 return MANIFEST_SUCCESS;
91}
92
93static enum manifest_return_code read_uint16(const struct fdt_node *node,
94 const char *property,
95 uint16_t *out)
96{
97 uint64_t value;
98
99 TRY(read_uint64(node, property, &value));
100
101 if (value > UINT16_MAX) {
102 return MANIFEST_ERROR_INTEGER_OVERFLOW;
103 }
104
105 *out = (uint16_t)value;
106 return MANIFEST_SUCCESS;
107}
108
109static enum manifest_return_code parse_vm(struct fdt_node *node,
110 struct manifest_vm *vm,
111 spci_vm_id_t vm_id)
112{
113 TRY(read_string(node, "debug_name", &vm->debug_name));
114 if (vm_id != HF_PRIMARY_VM_ID) {
115 TRY(read_string(node, "kernel_filename",
116 &vm->secondary.kernel_filename));
117 TRY(read_uint64(node, "mem_size", &vm->secondary.mem_size));
118 TRY(read_uint16(node, "vcpu_count", &vm->secondary.vcpu_count));
119 }
120 return MANIFEST_SUCCESS;
121}
122
123/**
124 * Parse manifest from FDT.
125 */
126enum manifest_return_code manifest_init(struct manifest *manifest,
127 struct memiter *fdt)
128{
129 char vm_name_buf[VM_NAME_BUF_SIZE];
130 struct fdt_node hyp_node;
131 size_t i = 0;
132 bool found_primary_vm = false;
133
134 memset_s(manifest, sizeof(*manifest), 0, sizeof(*manifest));
135
136 /* Find hypervisor node. */
137 if (!fdt_root_node(&hyp_node,
138 (const struct fdt_header *)memiter_base(fdt))) {
139 return MANIFEST_ERROR_CORRUPTED_FDT;
140 }
141 if (!fdt_find_child(&hyp_node, "")) {
142 return MANIFEST_ERROR_NO_ROOT_FDT_NODE;
143 }
144 if (!fdt_find_child(&hyp_node, "hypervisor")) {
145 return MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE;
146 }
147
148 /* Iterate over reserved VM IDs and check no such nodes exist. */
149 for (i = 0; i < HF_VM_ID_OFFSET; i++) {
150 spci_vm_id_t vm_id = (spci_vm_id_t)i;
151 struct fdt_node vm_node = hyp_node;
152 const char *vm_name = generate_vm_node_name(vm_name_buf, vm_id);
153
154 if (fdt_find_child(&vm_node, vm_name)) {
155 return MANIFEST_ERROR_RESERVED_VM_ID;
156 }
157 }
158
159 /* Iterate over VM nodes until we find one that does not exist. */
160 for (i = 0; i <= MAX_VMS; ++i) {
161 spci_vm_id_t vm_id = HF_VM_ID_OFFSET + i;
162 struct fdt_node vm_node = hyp_node;
163 const char *vm_name = generate_vm_node_name(vm_name_buf, vm_id);
164
165 if (!fdt_find_child(&vm_node, vm_name)) {
166 break;
167 }
168
169 if (i == MAX_VMS) {
170 return MANIFEST_ERROR_TOO_MANY_VMS;
171 }
172
173 if (vm_id == HF_PRIMARY_VM_ID) {
174 CHECK(found_primary_vm == false); /* sanity check */
175 found_primary_vm = true;
176 }
177
178 manifest->num_vms = i + 1;
179 TRY(parse_vm(&vm_node, &manifest->vm[i], vm_id));
180 }
181
182 if (!found_primary_vm) {
183 return MANIFEST_ERROR_NO_PRIMARY_VM;
184 }
185
186 return MANIFEST_SUCCESS;
187}
188
189const char *manifest_strerror(enum manifest_return_code ret_code)
190{
191 switch (ret_code) {
192 case MANIFEST_SUCCESS:
193 return "Success";
194 case MANIFEST_ERROR_CORRUPTED_FDT:
195 return "Manifest failed FDT validation";
196 case MANIFEST_ERROR_NO_ROOT_FDT_NODE:
197 return "Could not find root node of manifest";
198 case MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE:
199 return "Could not find \"hypervisor\" node in manifest";
200 case MANIFEST_ERROR_RESERVED_VM_ID:
201 return "Manifest defines a VM with a reserved ID";
202 case MANIFEST_ERROR_NO_PRIMARY_VM:
203 return "Manifest does not contain a primary VM entry";
204 case MANIFEST_ERROR_TOO_MANY_VMS:
205 return "Manifest specifies more VMs than Hafnium has "
206 "statically allocated space for";
207 case MANIFEST_ERROR_PROPERTY_NOT_FOUND:
208 return "Property not found";
209 case MANIFEST_ERROR_MALFORMED_STRING:
210 return "Malformed string property";
211 case MANIFEST_ERROR_MALFORMED_INTEGER:
212 return "Malformed integer property";
213 case MANIFEST_ERROR_INTEGER_OVERFLOW:
214 return "Integer overflow";
215 }
216
217 panic("Unexpected manifest return code.");
218}