@@ -640,6 +640,10 @@ void arch_domain_destroy(struct domain *d)
domain_vgic_free(d);
domain_vuart_free(d);
free_xenheap_page(d->shared_info);
+#ifdef CONFIG_ACPI
+ free_xenheap_pages(d->arch.efi_acpi_table,
+ get_order_from_bytes(d->arch.efi_acpi_len));
+#endif
}
void arch_domain_shutdown(struct domain *d)
@@ -12,6 +12,8 @@
#include <xen/libfdt/libfdt.h>
#include <xen/guest_access.h>
#include <xen/iocap.h>
+#include <xen/acpi.h>
+#include <acpi/actables.h>
#include <asm/device.h>
#include <asm/setup.h>
#include <asm/platform.h>
@@ -1354,6 +1356,101 @@ static int prepare_dtb(struct domain *d, struct kernel_info *kinfo)
return -EINVAL;
}
+#ifdef CONFIG_ACPI
+static int estimate_acpi_efi_size(struct domain *d, struct kernel_info *kinfo)
+{
+ size_t efi_size, acpi_size, madt_size;
+ u64 addr;
+ struct acpi_table_rsdp *rsdp_tbl;
+ struct acpi_table_header *table;
+
+ efi_size = estimate_efi_size(kinfo->mem.nr_banks);
+
+ acpi_size = ROUNDUP(sizeof(struct acpi_table_fadt), 8);
+ acpi_size += ROUNDUP(sizeof(struct acpi_table_stao), 8);
+
+ madt_size = sizeof(struct acpi_table_madt)
+ + sizeof(struct acpi_madt_generic_interrupt) * d->max_vcpus
+ + sizeof(struct acpi_madt_generic_distributor);
+ if ( d->arch.vgic.version == GIC_V3 )
+ madt_size += sizeof(struct acpi_madt_generic_redistributor)
+ * d->arch.vgic.nr_regions;
+ acpi_size += ROUNDUP(madt_size, 8);
+
+ addr = acpi_os_get_root_pointer();
+ if ( !addr )
+ {
+ printk("Unable to get acpi root pointer\n");
+ return -EINVAL;
+ }
+
+ rsdp_tbl = acpi_os_map_memory(addr, sizeof(struct acpi_table_rsdp));
+ if ( !rsdp_tbl )
+ {
+ printk("Unable to map RSDP table\n");
+ return -EINVAL;
+ }
+
+ table = acpi_os_map_memory(rsdp_tbl->xsdt_physical_address,
+ sizeof(struct acpi_table_header));
+ acpi_os_unmap_memory(rsdp_tbl, sizeof(struct acpi_table_rsdp));
+ if ( !table )
+ {
+ printk("Unable to map XSDT table\n");
+ return -EINVAL;
+ }
+
+ /* Add place for STAO table in XSDT table */
+ acpi_size += ROUNDUP(table->length + sizeof(u64), 8);
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+
+ acpi_size += ROUNDUP(sizeof(struct acpi_table_rsdp), 8);
+ d->arch.efi_acpi_len = PAGE_ALIGN(ROUNDUP(efi_size, 8)
+ + ROUNDUP(acpi_size, 8));
+
+ return 0;
+}
+
+static int prepare_acpi(struct domain *d, struct kernel_info *kinfo)
+{
+ int rc = 0;
+ int order;
+
+ rc = estimate_acpi_efi_size(d, kinfo);
+ if ( rc != 0 )
+ return rc;
+
+ order = get_order_from_bytes(d->arch.efi_acpi_len);
+ d->arch.efi_acpi_table = alloc_xenheap_pages(order, 0);
+ if ( d->arch.efi_acpi_table == NULL )
+ {
+ printk("unable to allocate memory!\n");
+ return -ENOMEM;
+ }
+ memset(d->arch.efi_acpi_table, 0, d->arch.efi_acpi_len);
+
+ /*
+ * For ACPI, Dom0 doesn't use kinfo->gnttab_start to get the grant table
+ * region. So we use it as the ACPI table mapped address. Also it needs to
+ * check if the size of grant table region is enough for those ACPI tables.
+ */
+ d->arch.efi_acpi_gpa = kinfo->gnttab_start;
+ if ( kinfo->gnttab_size < d->arch.efi_acpi_len )
+ {
+ printk("The grant table region is not enough to fit the ACPI tables!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else
+static int prepare_acpi(struct domain *d, struct kernel_info *kinfo)
+{
+ /* Only booting with ACPI will hit here */
+ BUG();
+ return -EINVAL;
+}
+#endif
static void dtb_load(struct kernel_info *kinfo)
{
void * __user dtb_virt = (void * __user)(register_t)kinfo->dtb_paddr;
@@ -1540,7 +1637,11 @@ int construct_dom0(struct domain *d)
allocate_memory(d, &kinfo);
find_gnttab_region(d, &kinfo);
- rc = prepare_dtb(d, &kinfo);
+ if ( acpi_disabled )
+ rc = prepare_dtb(d, &kinfo);
+ else
+ rc = prepare_acpi(d, &kinfo);
+
if ( rc < 0 )
return rc;
@@ -1,3 +1,4 @@
CFLAGS += -fshort-wchar
obj-y += boot.init.o runtime.o
+obj-$(CONFIG_ACPI) += efi-dom0.init.o
@@ -7,6 +7,7 @@
#include <xen/libfdt/libfdt.h>
#include <asm/setup.h>
#include <asm/smp.h>
+#include "efi-dom0.h"
void noreturn efi_xen_start(void *fdt_ptr, uint32_t fdt_size);
void __flush_dcache_area(const void *vaddr, unsigned long size);
@@ -17,9 +18,6 @@ void __flush_dcache_area(const void *vaddr, unsigned long size);
static struct file __initdata dtbfile;
static void __initdata *fdt;
static void __initdata *memmap;
-#ifdef CONFIG_ACPI
-static struct meminfo __initdata acpi_mem;
-#endif
static int __init setup_chosen_node(void *fdt, int *addr_cells, int *size_cells)
{
new file mode 100644
@@ -0,0 +1,59 @@
+/*
+ * efi-dom0.c - Domain0 EFI Boot Support
+ *
+ * Copyright (C) 2016 Shannon Zhao <shannon.zhao@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include "efi.h"
+#include "efi-dom0.h"
+#include <asm/setup.h>
+#include <asm/acpi.h>
+
+struct meminfo __initdata acpi_mem;
+/* Constant to indicate "Xen" in unicode u16 format */
+static const CHAR16 xen_efi_fw_vendor[] = {0x0058, 0x0065, 0x006E, 0x0000};
+
+size_t __init estimate_efi_size(int mem_nr_banks)
+{
+ size_t size;
+ size_t est_size = sizeof(EFI_SYSTEM_TABLE);
+ size_t ect_size = sizeof(EFI_CONFIGURATION_TABLE);
+ size_t emd_size = sizeof(EFI_MEMORY_DESCRIPTOR);
+ size_t fw_vendor_size = sizeof(xen_efi_fw_vendor);
+ int acpi_mem_nr_banks = 0;
+
+ if ( !acpi_disabled )
+ acpi_mem_nr_banks = acpi_mem.nr_banks;
+
+ size = ROUNDUP(est_size + ect_size + fw_vendor_size, 8);
+ /* plus 1 for new created tables */
+ size += ROUNDUP(emd_size * (mem_nr_banks + acpi_mem_nr_banks + 1), 8);
+
+ return size;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
new file mode 100644
@@ -0,0 +1,8 @@
+#ifndef __ARM_EFI_DOM0_H__
+#define __ARM_EFI_DOM0_H__
+
+#include <asm/setup.h>
+
+extern struct meminfo acpi_mem;
+
+#endif
@@ -51,6 +51,8 @@ void arch_init_memory(void);
void copy_from_paddr(void *dst, paddr_t paddr, unsigned long len);
+size_t estimate_efi_size(int mem_nr_banks);
+
int construct_dom0(struct domain *d);
void discard_initial_modules(void);