1 /*
2  * ARM DomU ACPI generation
3  *
4  * Copyright (C) 2016      Linaro Ltd.
5  *
6  * Author: Shannon Zhao <shannon.zhao@linaro.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published
10  * by the Free Software Foundation; version 2.1 only. with the special
11  * exception on linking described in file LICENSE.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  */
18 
19 #include "libxl_arm.h"
20 
21 #include <stdint.h>
22 
23 /* Below typedefs are useful for the headers under acpi/ */
24 typedef uint8_t u8;
25 typedef uint16_t u16;
26 typedef uint32_t u32;
27 typedef uint64_t u64;
28 typedef int64_t s64;
29 
30 #include <acpi/acconfig.h>
31 #include <acpi/actbl.h>
32 
33 #ifndef BITS_PER_LONG
34 #ifdef _LP64
35 #define BITS_PER_LONG 64
36 #else
37 #define BITS_PER_LONG 32
38 #endif
39 #endif
40 #define ACPI_MACHINE_WIDTH BITS_PER_LONG
41 #define COMPILER_DEPENDENT_INT64 int64_t
42 #define COMPILER_DEPENDENT_UINT64 uint64_t
43 
44 #include <acpi/actypes.h>
45 
46 _hidden
47 extern const unsigned char dsdt_anycpu_arm[];
48 _hidden
49 extern const int dsdt_anycpu_arm_len;
50 
51 #define ACPI_OEM_ID "Xen\0\0"
52 #define ACPI_OEM_TABLE_ID "ARM\0\0\0\0"
53 #define ACPI_ASL_COMPILER_ID "XL\0"
54 
55 enum {
56     RSDP,
57     XSDT,
58     GTDT,
59     MADT,
60     FADT,
61     DSDT,
62     MAX_TABLE_NUMS,
63 };
64 
65 struct acpitable {
66     uint64_t addr;
67     size_t size;
68 };
69 
libxl__estimate_madt_size(libxl__gc * gc,const libxl_domain_build_info * info,size_t * size)70 static int libxl__estimate_madt_size(libxl__gc *gc,
71                                      const libxl_domain_build_info *info,
72                                      size_t *size)
73 {
74     int rc = 0;
75 
76     switch (info->arch_arm.gic_version) {
77     case LIBXL_GIC_VERSION_V2:
78         *size = sizeof(struct acpi_table_madt) +
79                 ACPI_MADT_GICC_SIZE_v5 * info->max_vcpus +
80                 sizeof(struct acpi_madt_generic_distributor);
81         break;
82     case LIBXL_GIC_VERSION_V3:
83         *size = sizeof(struct acpi_table_madt) +
84                 ACPI_MADT_GICC_SIZE_v5 * info->max_vcpus +
85                 sizeof(struct acpi_madt_generic_distributor) +
86                 sizeof(struct acpi_madt_generic_redistributor);
87         break;
88     default:
89         LOG(ERROR, "Unknown GIC version");
90         *size = 0;
91         rc = ERROR_FAIL;
92         break;
93     }
94 
95     return rc;
96 }
97 
libxl__get_acpi_size(libxl__gc * gc,const libxl_domain_build_info * info,uint64_t * out)98 int libxl__get_acpi_size(libxl__gc *gc,
99                          const libxl_domain_build_info *info,
100                          uint64_t *out)
101 {
102     uint64_t size;
103     int rc = 0;
104 
105 
106     rc = libxl__estimate_madt_size(gc, info, &size);
107     if (rc < 0)
108         goto out;
109 
110     *out = ROUNDUP(size, 3) +
111            ROUNDUP(sizeof(struct acpi_table_rsdp), 3) +
112            ROUNDUP(sizeof(struct acpi_table_xsdt), 3) +
113            ROUNDUP(sizeof(struct acpi_table_gtdt), 3) +
114            ROUNDUP(sizeof(struct acpi_table_fadt), 3) +
115            ROUNDUP(sizeof(dsdt_anycpu_arm_len), 3);
116 
117 out:
118     return rc;
119 }
120 
libxl__allocate_acpi_tables(libxl__gc * gc,libxl_domain_build_info * info,struct xc_dom_image * dom,struct acpitable acpitables[])121 static int libxl__allocate_acpi_tables(libxl__gc *gc,
122                                        libxl_domain_build_info *info,
123                                        struct xc_dom_image *dom,
124                                        struct acpitable acpitables[])
125 {
126     int rc;
127     size_t size;
128 
129     acpitables[RSDP].addr = GUEST_ACPI_BASE;
130     acpitables[RSDP].size = sizeof(struct acpi_table_rsdp);
131     dom->acpi_modules[0].length += ROUNDUP(acpitables[RSDP].size, 3);
132 
133     acpitables[XSDT].addr = GUEST_ACPI_BASE + dom->acpi_modules[0].length;
134     /*
135      * Currently only 3 tables(GTDT, FADT, MADT) are pointed by XSDT. Alloc
136      * entries for them.
137      */
138     acpitables[XSDT].size = sizeof(struct acpi_table_xsdt) +
139                             sizeof(uint64_t) * 2;
140     dom->acpi_modules[0].length += ROUNDUP(acpitables[XSDT].size, 3);
141 
142     acpitables[GTDT].addr = GUEST_ACPI_BASE + dom->acpi_modules[0].length;
143     acpitables[GTDT].size = sizeof(struct acpi_table_gtdt);
144     dom->acpi_modules[0].length += ROUNDUP(acpitables[GTDT].size, 3);
145 
146     acpitables[MADT].addr = GUEST_ACPI_BASE + dom->acpi_modules[0].length;
147 
148     rc = libxl__estimate_madt_size(gc, info, &size);
149     if (rc < 0)
150         goto out;
151 
152     acpitables[MADT].size = size;
153     dom->acpi_modules[0].length += ROUNDUP(acpitables[MADT].size, 3);
154 
155     acpitables[FADT].addr = GUEST_ACPI_BASE + dom->acpi_modules[0].length;
156     acpitables[FADT].size = sizeof(struct acpi_table_fadt);
157     dom->acpi_modules[0].length += ROUNDUP(acpitables[FADT].size, 3);
158 
159     acpitables[DSDT].addr = GUEST_ACPI_BASE + dom->acpi_modules[0].length;
160     acpitables[DSDT].size = dsdt_anycpu_arm_len;
161     dom->acpi_modules[0].length += ROUNDUP(acpitables[DSDT].size, 3);
162 
163     assert(dom->acpi_modules[0].length <= GUEST_ACPI_SIZE);
164     dom->acpi_modules[0].data = libxl__zalloc(gc, dom->acpi_modules[0].length);
165 
166     rc = 0;
167 out:
168     return rc;
169 }
170 
calculate_checksum(void * table,uint32_t checksum_offset,uint32_t length)171 static void calculate_checksum(void *table, uint32_t checksum_offset,
172                                uint32_t length)
173 {
174     uint8_t *p, sum = 0;
175 
176     p = table;
177     p[checksum_offset] = 0;
178 
179     while (length--)
180         sum = sum + *p++;
181 
182     p = table;
183     p[checksum_offset] = -sum;
184 }
185 
make_acpi_rsdp(libxl__gc * gc,struct xc_dom_image * dom,struct acpitable acpitables[])186 static void make_acpi_rsdp(libxl__gc *gc, struct xc_dom_image *dom,
187                            struct acpitable acpitables[])
188 {
189     uint64_t offset = acpitables[RSDP].addr - GUEST_ACPI_BASE;
190     struct acpi_table_rsdp *rsdp = (void *)dom->acpi_modules[0].data + offset;
191 
192     memcpy(rsdp->signature, "RSD PTR ", sizeof(rsdp->signature));
193     BUILD_BUG_ON(sizeof(ACPI_OEM_ID) != sizeof(rsdp->oem_id));
194     memcpy(rsdp->oem_id, ACPI_OEM_ID, sizeof(rsdp->oem_id));
195     rsdp->length = acpitables[RSDP].size;
196     rsdp->revision = 0x02;
197     rsdp->xsdt_physical_address = acpitables[XSDT].addr;
198     calculate_checksum(rsdp,
199                        offsetof(struct acpi_table_rsdp, extended_checksum),
200                        acpitables[RSDP].size);
201 }
202 
make_acpi_header(struct acpi_table_header * h,const char * sig,size_t len,uint8_t rev)203 static void make_acpi_header(struct acpi_table_header *h, const char *sig,
204                              size_t len, uint8_t rev)
205 {
206     memcpy(h->signature, sig, 4);
207     h->length = len;
208     h->revision = rev;
209     BUILD_BUG_ON(sizeof(ACPI_OEM_ID) != sizeof(h->oem_id));
210     memcpy(h->oem_id, ACPI_OEM_ID, sizeof(h->oem_id));
211     BUILD_BUG_ON(sizeof(ACPI_OEM_TABLE_ID) != sizeof(h->oem_table_id));
212     memcpy(h->oem_table_id, ACPI_OEM_TABLE_ID, sizeof(h->oem_table_id));
213     h->oem_revision = 0;
214     BUILD_BUG_ON(sizeof(ACPI_ASL_COMPILER_ID) != sizeof(h->asl_compiler_id));
215     memcpy(h->asl_compiler_id, ACPI_ASL_COMPILER_ID,
216            sizeof(h->asl_compiler_id));
217     h->asl_compiler_revision = 0;
218     h->checksum = 0;
219 }
220 
make_acpi_xsdt(libxl__gc * gc,struct xc_dom_image * dom,struct acpitable acpitables[])221 static void make_acpi_xsdt(libxl__gc *gc, struct xc_dom_image *dom,
222                            struct acpitable acpitables[])
223 {
224     uint64_t offset = acpitables[XSDT].addr - GUEST_ACPI_BASE;
225     struct acpi_table_xsdt *xsdt = (void *)dom->acpi_modules[0].data + offset;
226 
227     xsdt->table_offset_entry[0] = acpitables[MADT].addr;
228     xsdt->table_offset_entry[1] = acpitables[GTDT].addr;
229     xsdt->table_offset_entry[2] = acpitables[FADT].addr;
230     make_acpi_header(&xsdt->header, "XSDT", acpitables[XSDT].size, 1);
231     calculate_checksum(xsdt, offsetof(struct acpi_table_header, checksum),
232                        acpitables[XSDT].size);
233 }
234 
make_acpi_gtdt(libxl__gc * gc,struct xc_dom_image * dom,struct acpitable acpitables[])235 static void make_acpi_gtdt(libxl__gc *gc, struct xc_dom_image *dom,
236                            struct acpitable acpitables[])
237 {
238     uint64_t offset = acpitables[GTDT].addr - GUEST_ACPI_BASE;
239     struct acpi_table_gtdt *gtdt = (void *)dom->acpi_modules[0].data + offset;
240 
241     gtdt->non_secure_el1_interrupt = GUEST_TIMER_PHYS_NS_PPI;
242     gtdt->non_secure_el1_flags =
243                              (ACPI_LEVEL_SENSITIVE << ACPI_GTDT_INTERRUPT_MODE)
244                              |(ACPI_ACTIVE_LOW << ACPI_GTDT_INTERRUPT_POLARITY);
245     gtdt->virtual_timer_interrupt = GUEST_TIMER_VIRT_PPI;
246     gtdt->virtual_timer_flags =
247                              (ACPI_LEVEL_SENSITIVE << ACPI_GTDT_INTERRUPT_MODE)
248                              |(ACPI_ACTIVE_LOW << ACPI_GTDT_INTERRUPT_POLARITY);
249 
250     gtdt->counter_block_addresss = ~((uint64_t)0);
251     gtdt->counter_read_block_address = ~((uint64_t)0);
252 
253     make_acpi_header(&gtdt->header, "GTDT", acpitables[GTDT].size, 2);
254     calculate_checksum(gtdt, offsetof(struct acpi_table_header, checksum),
255                        acpitables[GTDT].size);
256 }
257 
make_acpi_madt_gicc(void * table,int nr_cpus,uint64_t gicc_base)258 static void make_acpi_madt_gicc(void *table, int nr_cpus, uint64_t gicc_base)
259 {
260     int i;
261     struct acpi_madt_generic_interrupt *gicc = table;
262 
263     for (i = 0; i < nr_cpus; i++) {
264         gicc->header.type = ACPI_MADT_TYPE_GENERIC_INTERRUPT;
265         gicc->header.length = ACPI_MADT_GICC_SIZE_v5;
266         gicc->base_address = gicc_base;
267         gicc->cpu_interface_number = i;
268         gicc->arm_mpidr = libxl__compute_mpdir(i);
269         gicc->uid = i;
270         gicc->flags = ACPI_MADT_ENABLED;
271         gicc = table + ACPI_MADT_GICC_SIZE_v5;
272     }
273 }
274 
make_acpi_madt_gicd(void * table,uint64_t gicd_base,uint8_t gic_version)275 static void make_acpi_madt_gicd(void *table, uint64_t gicd_base,
276                                 uint8_t gic_version)
277 {
278     struct acpi_madt_generic_distributor *gicd = table;
279 
280     gicd->header.type = ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR;
281     gicd->header.length = sizeof(*gicd);
282     gicd->base_address = gicd_base;
283     /* This version field has no meaning before ACPI 5.1 errata. */
284     gicd->version = gic_version;
285 }
286 
make_acpi_madt_gicr(void * table,uint64_t gicr_base,uint64_t gicr_size)287 static void make_acpi_madt_gicr(void *table, uint64_t gicr_base,
288                                 uint64_t gicr_size)
289 {
290     struct acpi_madt_generic_redistributor *gicr = table;
291 
292     gicr->header.type = ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR;
293     gicr->header.length = sizeof(*gicr);
294     gicr->base_address = gicr_base;
295     gicr->length = gicr_size;
296 }
297 
make_acpi_madt(libxl__gc * gc,struct xc_dom_image * dom,libxl_domain_build_info * info,struct acpitable acpitables[])298 static int make_acpi_madt(libxl__gc *gc, struct xc_dom_image *dom,
299                           libxl_domain_build_info *info,
300                           struct acpitable acpitables[])
301 {
302     uint64_t offset = acpitables[MADT].addr - GUEST_ACPI_BASE;
303     void *table = dom->acpi_modules[0].data + offset;
304     struct acpi_table_madt *madt = table;
305     int rc = 0;
306 
307     switch (info->arch_arm.gic_version) {
308     case LIBXL_GIC_VERSION_V2:
309         table += sizeof(struct acpi_table_madt);
310         make_acpi_madt_gicc(table, info->max_vcpus, GUEST_GICC_BASE);
311 
312         table += ACPI_MADT_GICC_SIZE_v5 * info->max_vcpus;
313         make_acpi_madt_gicd(table, GUEST_GICD_BASE, ACPI_MADT_GIC_VERSION_V2);
314         break;
315     case LIBXL_GIC_VERSION_V3:
316         table += sizeof(struct acpi_table_madt);
317         make_acpi_madt_gicc(table, info->max_vcpus, 0);
318 
319         table += ACPI_MADT_GICC_SIZE_v5 * info->max_vcpus;
320         make_acpi_madt_gicd(table, GUEST_GICV3_GICD_BASE,
321                             ACPI_MADT_GIC_VERSION_V3);
322 
323         table += sizeof(struct acpi_madt_generic_distributor);
324         make_acpi_madt_gicr(table, GUEST_GICV3_GICR0_BASE,
325                             GUEST_GICV3_GICR0_SIZE);
326         break;
327     default:
328         LOG(ERROR, "Unknown GIC version");
329         rc = ERROR_FAIL;
330         goto out;
331     }
332 
333     make_acpi_header(&madt->header, "APIC", acpitables[MADT].size, 3);
334     calculate_checksum(madt, offsetof(struct acpi_table_header, checksum),
335                        acpitables[MADT].size);
336 
337 out:
338     return rc;
339 }
340 
make_acpi_fadt(libxl__gc * gc,struct xc_dom_image * dom,struct acpitable acpitables[])341 static void make_acpi_fadt(libxl__gc *gc, struct xc_dom_image *dom,
342                            struct acpitable acpitables[])
343 {
344     uint64_t offset = acpitables[FADT].addr - GUEST_ACPI_BASE;
345     struct acpi_table_fadt *fadt = (void *)dom->acpi_modules[0].data + offset;
346 
347     /* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */
348     fadt->flags = ACPI_FADT_HW_REDUCED;
349     fadt->arm_boot_flags = ACPI_FADT_PSCI_COMPLIANT | ACPI_FADT_PSCI_USE_HVC;
350 
351     /* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
352     fadt->minor_revision = 0x1;
353     fadt->dsdt = acpitables[DSDT].addr;
354 
355     make_acpi_header(&fadt->header, "FACP", acpitables[FADT].size, 5);
356     calculate_checksum(fadt, offsetof(struct acpi_table_header, checksum),
357                        acpitables[FADT].size);
358 }
359 
make_acpi_dsdt(libxl__gc * gc,struct xc_dom_image * dom,struct acpitable acpitables[])360 static void make_acpi_dsdt(libxl__gc *gc, struct xc_dom_image *dom,
361                            struct acpitable acpitables[])
362 {
363     uint64_t offset = acpitables[DSDT].addr - GUEST_ACPI_BASE;
364     void *dsdt = dom->acpi_modules[0].data + offset;
365 
366     memcpy(dsdt, dsdt_anycpu_arm, dsdt_anycpu_arm_len);
367 }
368 
libxl__prepare_acpi(libxl__gc * gc,libxl_domain_build_info * info,struct xc_dom_image * dom)369 int libxl__prepare_acpi(libxl__gc *gc, libxl_domain_build_info *info,
370                         struct xc_dom_image *dom)
371 {
372     const libxl_version_info *vers;
373     int rc = 0;
374     struct acpitable acpitables[MAX_TABLE_NUMS];
375 
376     vers = libxl_get_version_info(CTX);
377     if (vers == NULL) {
378         rc = ERROR_FAIL;
379         goto out;
380     }
381 
382     LOG(DEBUG, "constructing ACPI tables for Xen version %d.%d guest",
383         vers->xen_version_major, vers->xen_version_minor);
384 
385     dom->acpi_modules[0].data = NULL;
386     dom->acpi_modules[0].length = 0;
387     dom->acpi_modules[0].guest_addr_out = GUEST_ACPI_BASE;
388 
389     rc = libxl__allocate_acpi_tables(gc, info, dom, acpitables);
390     if (rc)
391         goto out;
392 
393     make_acpi_rsdp(gc, dom, acpitables);
394     make_acpi_xsdt(gc, dom, acpitables);
395     make_acpi_gtdt(gc, dom, acpitables);
396     rc = make_acpi_madt(gc, dom, info, acpitables);
397     if (rc)
398         goto out;
399 
400     make_acpi_fadt(gc, dom, acpitables);
401     make_acpi_dsdt(gc, dom, acpitables);
402 
403 out:
404     return rc;
405 }
406 
407 /*
408  * Local variables:
409  * mode: C
410  * c-basic-offset: 4
411  * indent-tabs-mode: nil
412  * End:
413  */
414