1 /*
2  *  efi-dom0.c - Domain0 EFI Boot Support
3  *
4  *  Copyright (C) 2016 Shannon Zhao <shannon.zhao@linaro.org>
5  *
6  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
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 General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
20  *
21  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22  */
23 
24 #include "efi.h"
25 #include <xen/sched.h>
26 #include <xen/pfn.h>
27 #include <xen/libfdt/libfdt.h>
28 #include <asm/setup.h>
29 #include <asm/acpi.h>
30 #include "../../../common/decompress.h"
31 #define XZ_EXTERN STATIC
32 #include "../../../common/xz/crc32.c"
33 
34 /* Constant to indicate "Xen" in unicode u16 format */
35 static const CHAR16 xen_efi_fw_vendor[] = {0x0058, 0x0065, 0x006E, 0x0000};
36 
estimate_efi_size(int mem_nr_banks)37 size_t __init estimate_efi_size(int mem_nr_banks)
38 {
39     size_t size;
40     size_t est_size = sizeof(EFI_SYSTEM_TABLE);
41     size_t ect_size = sizeof(EFI_CONFIGURATION_TABLE);
42     size_t emd_size = sizeof(EFI_MEMORY_DESCRIPTOR);
43     size_t fw_vendor_size = sizeof(xen_efi_fw_vendor);
44     int acpi_mem_nr_banks = 0;
45 
46     if ( !acpi_disabled )
47         acpi_mem_nr_banks = bootinfo.acpi.nr_banks;
48 
49     size = ROUNDUP(est_size + ect_size + fw_vendor_size, 8);
50     /* plus 1 for new created tables */
51     size += ROUNDUP(emd_size * (mem_nr_banks + acpi_mem_nr_banks + 1), 8);
52 
53     return size;
54 }
55 
acpi_create_efi_system_table(struct domain * d,struct membank tbl_add[])56 void __init acpi_create_efi_system_table(struct domain *d,
57                                          struct membank tbl_add[])
58 {
59     u64 table_addr, table_size, offset = 0;
60     u8 *base_ptr;
61     EFI_CONFIGURATION_TABLE *efi_conf_tbl;
62     EFI_SYSTEM_TABLE *efi_sys_tbl;
63 
64     table_addr = d->arch.efi_acpi_gpa
65                  + acpi_get_table_offset(tbl_add, TBL_EFIT);
66     table_size = sizeof(EFI_SYSTEM_TABLE) + sizeof(EFI_CONFIGURATION_TABLE)
67                  + sizeof(xen_efi_fw_vendor);
68     base_ptr = d->arch.efi_acpi_table
69                + acpi_get_table_offset(tbl_add, TBL_EFIT);
70     efi_sys_tbl = (EFI_SYSTEM_TABLE *)base_ptr;
71 
72     efi_sys_tbl->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE;
73     /* Specify the revision as 2.5 */
74     efi_sys_tbl->Hdr.Revision = (2 << 16 | 50);
75     efi_sys_tbl->Hdr.HeaderSize = table_size;
76 
77     efi_sys_tbl->FirmwareRevision = 1;
78     efi_sys_tbl->NumberOfTableEntries = 1;
79     offset += sizeof(EFI_SYSTEM_TABLE);
80     memcpy(base_ptr + offset, xen_efi_fw_vendor, sizeof(xen_efi_fw_vendor));
81     efi_sys_tbl->FirmwareVendor = (CHAR16 *)(table_addr + offset);
82 
83     offset += sizeof(xen_efi_fw_vendor);
84     efi_conf_tbl = (EFI_CONFIGURATION_TABLE *)(base_ptr + offset);
85     efi_conf_tbl->VendorGuid = (EFI_GUID)ACPI_20_TABLE_GUID;
86     efi_conf_tbl->VendorTable = (VOID *)tbl_add[TBL_RSDP].start;
87     efi_sys_tbl->ConfigurationTable = (EFI_CONFIGURATION_TABLE *)(table_addr
88                                                                   + offset);
89     xz_crc32_init();
90     efi_sys_tbl->Hdr.CRC32 = xz_crc32((uint8_t *)efi_sys_tbl,
91                                       efi_sys_tbl->Hdr.HeaderSize, 0);
92 
93     tbl_add[TBL_EFIT].start = table_addr;
94     tbl_add[TBL_EFIT].size = table_size;
95 }
96 
fill_efi_memory_descriptor(EFI_MEMORY_DESCRIPTOR * desc,UINT32 type,EFI_PHYSICAL_ADDRESS start,UINT64 size)97 static void __init fill_efi_memory_descriptor(EFI_MEMORY_DESCRIPTOR *desc,
98                                               UINT32 type,
99                                               EFI_PHYSICAL_ADDRESS start,
100                                               UINT64 size)
101 {
102     desc->Type = type;
103     desc->PhysicalStart = start;
104     BUG_ON(size & EFI_PAGE_MASK);
105     desc->NumberOfPages = EFI_SIZE_TO_PAGES(size);
106     desc->Attribute = EFI_MEMORY_WB;
107 }
108 
acpi_create_efi_mmap_table(struct domain * d,const struct meminfo * mem,struct membank tbl_add[])109 void __init acpi_create_efi_mmap_table(struct domain *d,
110                                        const struct meminfo *mem,
111                                        struct membank tbl_add[])
112 {
113     EFI_MEMORY_DESCRIPTOR *desc;
114     unsigned int i;
115     u8 *base_ptr;
116 
117     base_ptr = d->arch.efi_acpi_table
118                + acpi_get_table_offset(tbl_add, TBL_MMAP);
119     desc = (EFI_MEMORY_DESCRIPTOR *)base_ptr;
120 
121     for ( i = 0; i < mem->nr_banks; i++, desc++ )
122         fill_efi_memory_descriptor(desc, EfiConventionalMemory,
123                                    mem->bank[i].start, mem->bank[i].size);
124 
125     for ( i = 0; i < bootinfo.acpi.nr_banks; i++, desc++ )
126         fill_efi_memory_descriptor(desc, EfiACPIReclaimMemory,
127                                    bootinfo.acpi.bank[i].start,
128                                    bootinfo.acpi.bank[i].size);
129 
130     fill_efi_memory_descriptor(desc, EfiACPIReclaimMemory,
131                                d->arch.efi_acpi_gpa, d->arch.efi_acpi_len);
132 
133     tbl_add[TBL_MMAP].start = d->arch.efi_acpi_gpa
134                               + acpi_get_table_offset(tbl_add, TBL_MMAP);
135     tbl_add[TBL_MMAP].size = sizeof(EFI_MEMORY_DESCRIPTOR)
136                              * (mem->nr_banks + bootinfo.acpi.nr_banks + 1);
137 }
138 
139 /* Create /hypervisor/uefi node for efi properties. */
acpi_make_efi_nodes(void * fdt,struct membank tbl_add[])140 int __init acpi_make_efi_nodes(void *fdt, struct membank tbl_add[])
141 {
142     int res;
143 
144     res = fdt_begin_node(fdt, "uefi");
145     if ( res )
146         return res;
147 
148     res = fdt_property_u64(fdt, "xen,uefi-system-table",
149                            tbl_add[TBL_EFIT].start);
150     if ( res )
151         return res;
152 
153     res = fdt_property_u64(fdt, "xen,uefi-mmap-start",
154                            tbl_add[TBL_MMAP].start);
155     if ( res )
156         return res;
157 
158     res = fdt_property_u32(fdt, "xen,uefi-mmap-size",
159                            tbl_add[TBL_MMAP].size);
160     if ( res )
161         return res;
162 
163     res = fdt_property_u32(fdt, "xen,uefi-mmap-desc-size",
164                            sizeof(EFI_MEMORY_DESCRIPTOR));
165     if ( res )
166         return res;
167 
168     res = fdt_property_u32(fdt, "xen,uefi-mmap-desc-ver", 1);
169     if ( res )
170         return res;
171 
172     res = fdt_end_node(fdt);
173 
174     return res;
175 }
176 
177 /*
178  * Local variables:
179  * mode: C
180  * c-file-style: "BSD"
181  * c-basic-offset: 4
182  * indent-tabs-mode: nil
183  * End:
184  */
185