1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
5 * Copyright (c) 2018-2022 Intel Corporation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 #include <types.h>
29 #include <rtl.h>
30 #include "acpi.h"
31 #include <asm/pgtable.h>
32 #include <asm/ioapic.h>
33 #include <logmsg.h>
34 #include <acrn_common.h>
35 #include <util.h>
36 #include <asm/e820.h>
37 #include <boot.h>
38
39 static struct acpi_table_rsdp *acpi_rsdp;
40
found_rsdp(char * base,uint64_t length)41 static struct acpi_table_rsdp *found_rsdp(char *base, uint64_t length)
42 {
43 struct acpi_table_rsdp *rsdp, *ret = NULL;
44 uint64_t ofs;
45
46 /* search on 16-byte boundaries */
47 for (ofs = 0UL; ofs < length; ofs += 16UL) {
48 rsdp = (struct acpi_table_rsdp *)(base + ofs);
49
50 /* compare signature, validate checksum */
51 if ((strncmp(rsdp->signature, ACPI_SIG_RSDP, strnlen_s(ACPI_SIG_RSDP, sizeof(rsdp->signature))) == 0)
52 && (calculate_sum8(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) == 0U)) {
53 ret = rsdp;
54 break;
55 }
56 }
57
58 return ret;
59 }
60
61 /* RSDP parsed from BIOS region should exist.
62 * If it is NULL, the hypervisor can't be booted
63 */
get_rsdp(void)64 static struct acpi_table_rsdp *get_rsdp(void)
65 {
66 return acpi_rsdp;
67 }
68
init_acpi(void)69 void init_acpi(void)
70 {
71 struct acpi_table_rsdp *rsdp = NULL;
72
73 rsdp = (struct acpi_table_rsdp *)(get_acrn_boot_info()->acpi_rsdp_va);
74 if (rsdp == NULL) {
75 uint16_t *addr;
76
77 /* EBDA is addressed by the 16 bit pointer at 0x40E */
78 addr = (uint16_t *)hpa2hva(0x40eUL);
79
80 rsdp = found_rsdp((char *)hpa2hva((uint64_t)(*addr) << 4U), 0x400UL);
81 }
82 if (rsdp == NULL) {
83 /* Check the upper memory BIOS space, 0xe0000 - 0xfffff. */
84 rsdp = found_rsdp((char *)hpa2hva(0xe0000UL), 0x20000UL);
85 }
86
87 if (rsdp == NULL) {
88 /* Check ACPI RECLAIM region, there might be multiple ACPI reclaimable regions. */
89 uint32_t i;
90 const struct e820_entry *entry = get_e820_entry();
91 uint32_t entries_count = get_e820_entries_count();
92
93 for (i = 0U; i < entries_count; i++) {
94 if (entry[i].type == E820_TYPE_ACPI_RECLAIM) {
95 rsdp = found_rsdp((char *)hpa2hva(entry[i].baseaddr), entry[i].length);
96 if (rsdp != NULL) {
97 break;
98 }
99 }
100 }
101 }
102
103 if (rsdp == NULL) {
104 panic("No RSDP is found");
105 }
106
107 /* After RSDP is parsed, it will be assigned to acpi_rsdp */
108 acpi_rsdp = rsdp;
109 }
110
probe_table(uint64_t address,const char * signature)111 static bool probe_table(uint64_t address, const char *signature)
112 {
113 void *va = hpa2hva(address);
114 struct acpi_table_header *table = (struct acpi_table_header *)va;
115 bool ret;
116
117 if (strncmp(table->signature, signature, ACPI_NAME_SIZE) != 0) {
118 ret = false;
119 } else {
120 ret = true;
121 }
122
123 return ret;
124 }
125
get_acpi_tbl(const char * signature)126 void *get_acpi_tbl(const char *signature)
127 {
128 struct acpi_table_rsdp *rsdp;
129 struct acpi_table_rsdt *rsdt;
130 struct acpi_table_xsdt *xsdt;
131 uint64_t addr = 0UL;
132 uint32_t i, count;
133
134 /* the returned RSDP should always exist. Otherwise the hypervisor
135 * can't be booted.
136 */
137 rsdp = get_rsdp();
138
139 if ((rsdp->revision >= 2U) && (rsdp->xsdt_physical_address != 0UL)) {
140 /*
141 * AcpiOsGetRootPointer only verifies the checksum for
142 * the version 1.0 portion of the RSDP. Version 2.0 has
143 * an additional checksum that we verify first.
144 */
145 xsdt = (struct acpi_table_xsdt *)hpa2hva(rsdp->xsdt_physical_address);
146 count = (xsdt->header.length - sizeof(struct acpi_table_header)) / sizeof(uint64_t);
147
148 for (i = 0U; i < count; i++) {
149 if (probe_table(xsdt->table_offset_entry[i], signature)) {
150 addr = xsdt->table_offset_entry[i];
151 break;
152 }
153 }
154 } else {
155 /* Root table is an RSDT (32-bit physical addresses) */
156 rsdt = (struct acpi_table_rsdt *)hpa2hva((uint64_t)rsdp->rsdt_physical_address);
157 count = (rsdt->header.length - sizeof(struct acpi_table_header)) / sizeof(uint32_t);
158
159 for (i = 0U; i < count; i++) {
160 if (probe_table(rsdt->table_offset_entry[i], signature)) {
161 addr = rsdt->table_offset_entry[i];
162 break;
163 }
164 }
165 }
166
167 return hpa2hva(addr);
168 }
169
170 /* TODO: As ACRN supports only x2APIC mode, we need to
171 * check upon using x2APIC APIC entries (Type 9) in MADT instead
172 * of Type 0
173 */
174 static uint16_t
local_parse_madt(struct acpi_table_madt * madt,uint32_t lapic_id_array[MAX_PCPU_NUM])175 local_parse_madt(struct acpi_table_madt *madt, uint32_t lapic_id_array[MAX_PCPU_NUM])
176 {
177 uint16_t pcpu_num = 0U;
178 struct acpi_madt_local_apic *processor;
179 struct acpi_table_madt *madt_ptr;
180 void *first, *end, *iterator;
181 struct acpi_subtable_header *entry;
182
183 madt_ptr = madt;
184
185 first = madt_ptr + 1;
186 end = (void *)madt_ptr + madt_ptr->header.length;
187
188 for (iterator = first; (iterator) < (end); iterator += entry->length) {
189 entry = (struct acpi_subtable_header *)iterator;
190 if (entry->length < sizeof(struct acpi_subtable_header)) {
191 break;
192 }
193
194 if (entry->type == ACPI_MADT_TYPE_LOCAL_APIC) {
195 processor = (struct acpi_madt_local_apic *)iterator;
196 if ((processor->lapic_flags & ACPI_MADT_ENABLED) != 0U) {
197 if (pcpu_num < MAX_PCPU_NUM) {
198 lapic_id_array[pcpu_num] = processor->id;
199 }
200 pcpu_num++;
201 }
202 }
203 }
204
205 return pcpu_num;
206 }
207
208 /* The lapic_id info gotten from madt will be returned in lapic_id_array */
parse_madt(uint32_t lapic_id_array[MAX_PCPU_NUM])209 uint16_t parse_madt(uint32_t lapic_id_array[MAX_PCPU_NUM])
210 {
211 uint16_t ret = 0U;
212 struct acpi_table_madt *madt = (struct acpi_table_madt *)get_acpi_tbl(ACPI_SIG_MADT);
213
214 if (madt != NULL) {
215 ret = local_parse_madt(madt, lapic_id_array);
216 }
217
218 return ret;
219 }
220
parse_madt_ioapic(struct ioapic_info * ioapic_id_array)221 uint8_t parse_madt_ioapic(struct ioapic_info *ioapic_id_array)
222 {
223 uint8_t ioapic_idx = 0U;
224 uint64_t entry, end;
225 const struct acpi_madt_ioapic *ioapic;
226 const struct acpi_table_madt *madt = (const struct acpi_table_madt *)get_acpi_tbl(ACPI_SIG_MADT);
227
228 if (madt != NULL) {
229 end = (uint64_t)madt + madt->header.length;
230
231 for (entry = (uint64_t)(madt + 1); entry < end; entry += ioapic->header.length) {
232 ioapic = (const struct acpi_madt_ioapic *)entry;
233
234 if (ioapic->header.type == ACPI_MADT_TYPE_IOAPIC) {
235 if (ioapic_idx < CONFIG_MAX_IOAPIC_NUM) {
236 ioapic_id_array[ioapic_idx].id = ioapic->id;
237 ioapic_id_array[ioapic_idx].addr = ioapic->addr;
238 ioapic_id_array[ioapic_idx].gsi_base = ioapic->gsi_base;
239 }
240 ioapic_idx++;
241 }
242 }
243 }
244
245 return ioapic_idx;
246 }
247
parse_hpet(void)248 void *parse_hpet(void)
249 {
250 const struct acpi_table_hpet *hpet = (const struct acpi_table_hpet *)get_acpi_tbl(ACPI_SIG_HPET);
251 uint64_t addr = 0UL;
252
253 if (hpet != NULL) {
254 addr = hpet->address.address;
255 }
256
257 return hpa2hva(addr);
258 }
259