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