1 /*
2  * HVM OVMF UEFI support.
3  *
4  * Bei Guan, gbtju85@gmail.com
5  * Andrei Warkentin, andreiw@motorola.com
6  * Leendert van Doorn, leendert@watson.ibm.com
7  * Copyright (c) 2005, International Business Machines Corporation.
8  * Copyright (c) 2006, Keir Fraser, XenSource Inc.
9  * Copyright (c) 2011, Citrix Inc.
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms and conditions of the GNU General Public License,
13  * version 2, as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  *
20  * You should have received a copy of the GNU General Public License along with
21  * this program; If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "config.h"
25 #include "smbios_types.h"
26 #include "libacpi.h"
27 #include "apic_regs.h"
28 #include "../rombios/config.h"
29 #include "util.h"
30 #include "pci_regs.h"
31 #include "hypercall.h"
32 
33 #include <xen/hvm/params.h>
34 #include <xen/hvm/ioreq.h>
35 #include <xen/memory.h>
36 
37 #define OVMF_MAXOFFSET          0x000FFFFFULL
38 #define OVMF_END                0x100000000ULL
39 #define LOWCHUNK_BEGIN          0x000F0000
40 #define LOWCHUNK_SIZE           0x00010000
41 #define LOWCHUNK_MAXOFFSET      0x0000FFFF
42 #define OVMF_INFO_PHYSICAL_ADDRESS 0x00001000
43 
44 #define OVMF_INFO_MAX_TABLES 4
45 struct ovmf_info {
46     char signature[14]; /* XenHVMOVMF\0\0\0\0 */
47     uint8_t length;     /* Length of this struct */
48     uint8_t checksum;   /* Set such that the sum over bytes 0..length == 0 */
49     /*
50      * Physical address of an array of tables_nr elements.
51      *
52      * Each element is a 64 bit value containing the physical address
53      * of a BIOS table.
54      */
55     uint64_t tables;
56     uint32_t tables_nr;
57     /*
58      * Physical address of the e820 table, contains e820_nr entries.
59      */
60     uint64_t e820;
61     uint32_t e820_nr;
62 } __attribute__ ((packed));
63 
ovmf_setup_bios_info(void)64 static void ovmf_setup_bios_info(void)
65 {
66     struct ovmf_info *info = (void *)OVMF_INFO_PHYSICAL_ADDRESS;
67 
68     *info = (struct ovmf_info) {
69         .signature = "XenHVMOVMF",
70         .length = sizeof(*info)
71     };
72 }
73 
ovmf_finish_bios_info(void)74 static void ovmf_finish_bios_info(void)
75 {
76     struct ovmf_info *info = (void *)OVMF_INFO_PHYSICAL_ADDRESS;
77     uint32_t i;
78     uint8_t checksum;
79 
80     checksum = 0;
81     for ( i = 0; i < info->length; i++ )
82         checksum += ((uint8_t *)(info))[i];
83 
84     info->checksum = -checksum;
85 }
86 
ovmf_load(const struct bios_config * config,void * bios_addr,uint32_t bios_length,void * unused_addr)87 static void ovmf_load(const struct bios_config *config,
88                       void *bios_addr, uint32_t bios_length,
89                       void *unused_addr)
90 {
91     xen_pfn_t mfn;
92     uint64_t addr = OVMF_END
93         - ((bios_length + OVMF_MAXOFFSET) & ~OVMF_MAXOFFSET);
94     uint64_t ovmf_end = addr + bios_length;
95 
96     ovmf_config.bios_address = addr;
97     ovmf_config.image_size = bios_length;
98 
99     /* Copy low-reset vector portion. */
100     memcpy((void *)LOWCHUNK_BEGIN,
101            (uint8_t *)bios_addr + bios_length - LOWCHUNK_SIZE,
102            LOWCHUNK_SIZE);
103 
104     /* Ensure we have backing page prior to moving FD. */
105     while ( (addr >> PAGE_SHIFT) != (ovmf_end >> PAGE_SHIFT) )
106     {
107         mfn = (uint32_t) (addr >> PAGE_SHIFT);
108         addr += PAGE_SIZE;
109         mem_hole_populate_ram(mfn, 1);
110     }
111 
112     /* Check that source and destination does not overlaps. */
113     BUG_ON(addr + bios_length > (unsigned)bios_addr &&
114            addr < (unsigned)bios_addr + bios_length);
115     /* Copy FD. */
116     memcpy((void *)ovmf_config.bios_address, bios_addr, bios_length);
117 }
118 
ovmf_acpi_build_tables(void)119 static void ovmf_acpi_build_tables(void)
120 {
121     struct acpi_config config = {
122         .dsdt_anycpu = dsdt_anycpu_qemu_xen,
123         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
124         .dsdt_15cpu = NULL,
125         .dsdt_15cpu_len = 0
126     };
127 
128     hvmloader_acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
129 }
130 
ovmf_create_smbios_tables(void)131 static void ovmf_create_smbios_tables(void)
132 {
133     hvm_write_smbios_tables(
134         SMBIOS_PHYSICAL_ADDRESS,
135         SMBIOS_PHYSICAL_ADDRESS + sizeof(struct smbios_entry_point),
136         SMBIOS_PHYSICAL_END);
137 }
138 
ovmf_setup_e820(void)139 static void ovmf_setup_e820(void)
140 {
141     struct ovmf_info *info = (void *)OVMF_INFO_PHYSICAL_ADDRESS;
142     struct e820entry *e820 = scratch_alloc(sizeof(struct e820entry)*16, 0);
143     info->e820 = (uint32_t)e820;
144 
145     /* Reserve LOWCHUNK_BEGIN to 0x100000 as well, that's reset vector. */
146     info->e820_nr = build_e820_table(e820, 0, LOWCHUNK_BEGIN);
147     dump_e820_table(e820, info->e820_nr);
148 }
149 
150 struct bios_config ovmf_config =  {
151     .name = "OVMF",
152 
153     .bios_load = ovmf_load,
154 
155     .load_roms = 0,
156 
157     .bios_info_setup = ovmf_setup_bios_info,
158     .bios_info_finish = ovmf_finish_bios_info,
159 
160     .e820_setup = ovmf_setup_e820,
161 
162     .acpi_build_tables = ovmf_acpi_build_tables,
163     .create_mp_tables = NULL,
164     .create_smbios_tables = ovmf_create_smbios_tables,
165     .create_pir_tables = NULL,
166 };
167 
168 /*
169  * Local variables:
170  * mode: C
171  * c-file-style: "BSD"
172  * c-basic-offset: 4
173  * tab-width: 4
174  * indent-tabs-mode: nil
175  * End:
176  */
177