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