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 <asm/host_pm.h>
35 #include <pci.h>
36 #include <acrn_common.h>
37 #include <asm/rtcm.h>
38 
39 /* Per ACPI spec:
40  * There are two fundamental types of ACPI tables:
41  *
42  * Tables that contain AML code produced from the ACPI Source Language (ASL).
43  * These include the DSDT, any SSDTs, and sometimes OEM-specific tables (OEMx).
44  *
45  * Tables that contain simple data and no AML byte code. These types of tables
46  * are known as ACPI Data Tables. They include tables such as the FADT, MADT,
47  * ECDT, SRAT, etc. -essentially any table other than a DSDT or SSDT.
48  *
49  * The second type of table, the ACPI Data Table, could be parsed here.
50  *
51  * When ACRN go FuSa, the platform ACPI data should be fixed and this file is not needed.
52  */
53 
54 /* get a dword value from given table and its offset */
get_acpi_dt_dword(const uint8_t * dt_addr,uint32_t dt_offset)55 static inline uint32_t get_acpi_dt_dword(const uint8_t *dt_addr, uint32_t dt_offset)
56 {
57 	return *(uint32_t *)(dt_addr + dt_offset);
58 }
59 
60 /* get a qword value from given table and its offset */
get_acpi_dt_qword(const uint8_t * dt_addr,uint32_t dt_offset)61 static inline uint64_t get_acpi_dt_qword(const uint8_t *dt_addr, uint32_t dt_offset)
62 {
63 	return *(uint64_t *)(dt_addr + dt_offset);
64 }
65 
66 /* get a GAS struct from given table and its offset.
67  * ACPI table stores packed gas, but it is not guaranteed that
68  * struct acrn_acpi_generic_address is packed, so do not use memcpy in function.
69  * @pre dt_addr != NULL && gas != NULL
70  */
get_acpi_dt_gas(const uint8_t * dt_addr,uint32_t dt_offset,struct acrn_acpi_generic_address * gas)71 static inline void get_acpi_dt_gas(const uint8_t *dt_addr, uint32_t dt_offset, struct acrn_acpi_generic_address *gas)
72 {
73 	struct packed_gas *dt_gas = (struct packed_gas *)(dt_addr + dt_offset);
74 
75 	gas->space_id = dt_gas->space_id;
76 	gas->bit_width = dt_gas->bit_width;
77 	gas->bit_offset = dt_gas->bit_offset;
78 	gas->access_size = dt_gas->access_size;
79 	gas->address = dt_gas->address;
80 }
81 
82 /* @pre facp_addr != NULL */
get_facs_table(const uint8_t * facp_addr)83 static void *get_facs_table(const uint8_t *facp_addr)
84 {
85 	uint8_t *facs_addr, *facs_x_addr;
86 	uint32_t signature, length;
87 	struct acpi_table_header *table = (struct acpi_table_header *)facp_addr;
88 
89 	facs_addr = (uint8_t *)(uint64_t)get_acpi_dt_dword(facp_addr, OFFSET_FACS_ADDR);
90 
91 	if (table->revision >= 2U) {
92 		facs_x_addr = (uint8_t *)get_acpi_dt_qword(facp_addr, OFFSET_FACS_X_ADDR);
93 
94 		if (facs_x_addr != NULL) {
95 			facs_addr = facs_x_addr;
96 		}
97 	}
98 
99 	if (facs_addr != NULL) {
100 		signature = get_acpi_dt_dword(facs_addr, OFFSET_FACS_SIGNATURE);
101 
102 		if (signature != ACPI_SIG_FACS) {
103 			facs_addr = NULL;
104 		} else {
105 			length = get_acpi_dt_dword(facs_addr, OFFSET_FACS_LENGTH);
106 
107 			if (length < 64U) {
108 				facs_addr = NULL;
109 			}
110 		}
111 	}
112 	return (void *)facs_addr;
113 }
114 
115 /* @pre mcfg_addr != NULL */
parse_mcfg_allocation_tables(const uint8_t * mcfg_addr)116 static struct acpi_mcfg_allocation *parse_mcfg_allocation_tables(const uint8_t *mcfg_addr)
117 {
118 	struct acpi_mcfg_allocation *mcfg_table = NULL;
119 	uint32_t length = get_acpi_dt_dword(mcfg_addr, OFFSET_MCFG_LENGTH);
120 
121 	if (length > OFFSET_MCFG_ENTRY1) {
122 		pr_fatal("Multiple PCI segment groups is not supported!");
123 	} else {
124 		mcfg_table = (struct acpi_mcfg_allocation *)(mcfg_addr + OFFSET_MCFG_ENTRY0_BASE);
125 	}
126 	return mcfg_table;
127 }
128 
129 /* put all ACPI fix up code here */
acpi_fixup(void)130 int32_t acpi_fixup(void)
131 {
132 	uint8_t *facp_addr = NULL, *facs_addr = NULL, *mcfg_addr = NULL, *rtct_tbl_addr = NULL;
133 	struct acpi_mcfg_allocation *mcfg_table = NULL;
134 	int32_t ret = 0;
135 	struct acrn_acpi_generic_address pm1a_cnt, pm1a_evt;
136 	struct pm_s_state_data *sx_data = get_host_sstate_data();
137 
138 	facp_addr = (uint8_t *)get_acpi_tbl(ACPI_SIG_FADT);
139 	if (facp_addr != NULL) {
140 		get_acpi_dt_gas(facp_addr, OFFSET_PM1A_EVT, &pm1a_evt);
141 		get_acpi_dt_gas(facp_addr, OFFSET_PM1A_CNT, &pm1a_cnt);
142 		(void)memcpy_s((void *)&sx_data->pm1a_evt, sizeof(struct acrn_acpi_generic_address),
143 				(const void *)&pm1a_evt, sizeof(struct acrn_acpi_generic_address));
144 		(void)memcpy_s((void *)&sx_data->pm1a_cnt, sizeof(struct acrn_acpi_generic_address),
145 				(const void *)&pm1a_cnt, sizeof(struct acrn_acpi_generic_address));
146 
147 		facs_addr = (uint8_t *)get_facs_table(facp_addr);
148 		if (facs_addr != NULL) {
149 			sx_data->wake_vector_32 = (uint32_t *)(facs_addr + OFFSET_WAKE_VECTOR_32);
150 			sx_data->wake_vector_64 = (uint64_t *)(facs_addr + OFFSET_WAKE_VECTOR_64);
151 		}
152 
153 		const struct acpi_table_header *table = (const struct acpi_table_header *)facp_addr;
154 
155 		if (table->revision >= 2U) {
156 			struct acpi_reset_reg *rr_data = get_host_reset_reg_data();
157 
158 			get_acpi_dt_gas(facp_addr, OFFSET_RESET_REGISTER, &(rr_data->reg));
159 			rr_data->val = *(facp_addr + OFFSET_RESET_VALUE);
160 		}
161 	}
162 
163 	mcfg_addr = (uint8_t *)get_acpi_tbl(ACPI_SIG_MCFG);
164 	if (mcfg_addr != NULL) {
165 		mcfg_table = parse_mcfg_allocation_tables(mcfg_addr);
166 		if (mcfg_table != NULL) {
167 			set_mmcfg_region((struct pci_mmcfg_region*)mcfg_table);
168 		}
169 	}
170 
171 	rtct_tbl_addr = (uint8_t *)get_acpi_tbl(ACPI_SIG_RTCT);
172 	if (rtct_tbl_addr == NULL) {
173 		rtct_tbl_addr = (uint8_t *)get_acpi_tbl(ACPI_SIG_RTCT_V2);
174 	}
175 
176 	if (rtct_tbl_addr != NULL) {
177 		set_rtct_tbl((void *)rtct_tbl_addr);
178 	}
179 
180 	if ((facp_addr == NULL) || (facs_addr == NULL)
181 				|| (mcfg_addr == NULL) || (mcfg_table == NULL)) {
182 		ret = -1;
183 	}
184 
185 	return ret;
186 }
187