xref: /openbmc/linux/drivers/acpi/acpica/tbxfroot.c (revision 6d21fb7d)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: tbxfroot - Find the root ACPI table (RSDT)
5  *
6  * Copyright (C) 2000 - 2023, Intel Corp.
7  *
8  *****************************************************************************/
9 
10 #include <acpi/acpi.h>
11 #include "accommon.h"
12 #include "actables.h"
13 
14 #define _COMPONENT          ACPI_TABLES
15 ACPI_MODULE_NAME("tbxfroot")
16 
17 /*******************************************************************************
18  *
19  * FUNCTION:    acpi_tb_get_rsdp_length
20  *
21  * PARAMETERS:  rsdp                - Pointer to RSDP
22  *
23  * RETURN:      Table length
24  *
25  * DESCRIPTION: Get the length of the RSDP
26  *
27  ******************************************************************************/
28 u32 acpi_tb_get_rsdp_length(struct acpi_table_rsdp *rsdp)
29 {
30 
31 	if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) {
32 
33 		/* BAD Signature */
34 
35 		return (0);
36 	}
37 
38 	/* "Length" field is available if table version >= 2 */
39 
40 	if (rsdp->revision >= 2) {
41 		return (rsdp->length);
42 	} else {
43 		return (ACPI_RSDP_CHECKSUM_LENGTH);
44 	}
45 }
46 
47 /*******************************************************************************
48  *
49  * FUNCTION:    acpi_tb_validate_rsdp
50  *
51  * PARAMETERS:  rsdp                - Pointer to unvalidated RSDP
52  *
53  * RETURN:      Status
54  *
55  * DESCRIPTION: Validate the RSDP (ptr)
56  *
57  ******************************************************************************/
58 
59 acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
60 {
61 
62 	/*
63 	 * The signature and checksum must both be correct
64 	 *
65 	 * Note: Sometimes there exists more than one RSDP in memory; the valid
66 	 * RSDP has a valid checksum, all others have an invalid checksum.
67 	 */
68 	if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) {
69 
70 		/* Nope, BAD Signature */
71 
72 		return (AE_BAD_SIGNATURE);
73 	}
74 
75 	/* Check the standard checksum */
76 
77 	if (acpi_ut_checksum((u8 *)rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
78 		return (AE_BAD_CHECKSUM);
79 	}
80 
81 	/* Check extended checksum if table version >= 2 */
82 
83 	if ((rsdp->revision >= 2) &&
84 	    (acpi_ut_checksum((u8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
85 		return (AE_BAD_CHECKSUM);
86 	}
87 
88 	return (AE_OK);
89 }
90 
91 /*******************************************************************************
92  *
93  * FUNCTION:    acpi_find_root_pointer
94  *
95  * PARAMETERS:  table_address           - Where the table pointer is returned
96  *
97  * RETURN:      Status, RSDP physical address
98  *
99  * DESCRIPTION: Search lower 1Mbyte of memory for the root system descriptor
100  *              pointer structure. If it is found, set *RSDP to point to it.
101  *
102  * NOTE1:       The RSDP must be either in the first 1K of the Extended
103  *              BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
104  *              Only a 32-bit physical address is necessary.
105  *
106  * NOTE2:       This function is always available, regardless of the
107  *              initialization state of the rest of ACPI.
108  *
109  ******************************************************************************/
110 
111 acpi_status ACPI_INIT_FUNCTION
112 acpi_find_root_pointer(acpi_physical_address *table_address)
113 {
114 	u8 *table_ptr;
115 	u8 *mem_rover;
116 	u32 physical_address;
117 	u32 ebda_window_size;
118 
119 	ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
120 
121 	/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
122 
123 	table_ptr = acpi_os_map_memory((acpi_physical_address)
124 				       ACPI_EBDA_PTR_LOCATION,
125 				       ACPI_EBDA_PTR_LENGTH);
126 	if (!table_ptr) {
127 		ACPI_ERROR((AE_INFO,
128 			    "Could not map memory at 0x%8.8X for length %u",
129 			    ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
130 
131 		return_ACPI_STATUS(AE_NO_MEMORY);
132 	}
133 
134 	ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
135 
136 	/* Convert segment part to physical address */
137 
138 	physical_address <<= 4;
139 	acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
140 
141 	/* EBDA present? */
142 
143 	/*
144 	 * Check that the EBDA pointer from memory is sane and does not point
145 	 * above valid low memory
146 	 */
147 	if (physical_address > 0x400 && physical_address < 0xA0000) {
148 		/*
149 		 * Calculate the scan window size
150 		 * The EBDA is not guaranteed to be larger than a ki_b and in case
151 		 * that it is smaller, the scanning function would leave the low
152 		 * memory and continue to the VGA range.
153 		 */
154 		ebda_window_size = ACPI_MIN(ACPI_EBDA_WINDOW_SIZE,
155 					    0xA0000 - physical_address);
156 
157 		/*
158 		 * 1b) Search EBDA paragraphs
159 		 */
160 		table_ptr = acpi_os_map_memory((acpi_physical_address)
161 					       physical_address,
162 					       ebda_window_size);
163 		if (!table_ptr) {
164 			ACPI_ERROR((AE_INFO,
165 				    "Could not map memory at 0x%8.8X for length %u",
166 				    physical_address, ebda_window_size));
167 
168 			return_ACPI_STATUS(AE_NO_MEMORY);
169 		}
170 
171 		mem_rover =
172 		    acpi_tb_scan_memory_for_rsdp(table_ptr, ebda_window_size);
173 		acpi_os_unmap_memory(table_ptr, ebda_window_size);
174 
175 		if (mem_rover) {
176 
177 			/* Return the physical address */
178 
179 			physical_address +=
180 			    (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
181 
182 			*table_address =
183 			    (acpi_physical_address)physical_address;
184 			return_ACPI_STATUS(AE_OK);
185 		}
186 	}
187 
188 	/*
189 	 * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
190 	 */
191 	table_ptr = acpi_os_map_memory((acpi_physical_address)
192 				       ACPI_HI_RSDP_WINDOW_BASE,
193 				       ACPI_HI_RSDP_WINDOW_SIZE);
194 
195 	if (!table_ptr) {
196 		ACPI_ERROR((AE_INFO,
197 			    "Could not map memory at 0x%8.8X for length %u",
198 			    ACPI_HI_RSDP_WINDOW_BASE,
199 			    ACPI_HI_RSDP_WINDOW_SIZE));
200 
201 		return_ACPI_STATUS(AE_NO_MEMORY);
202 	}
203 
204 	mem_rover =
205 	    acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
206 	acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
207 
208 	if (mem_rover) {
209 
210 		/* Return the physical address */
211 
212 		physical_address = (u32)
213 		    (ACPI_HI_RSDP_WINDOW_BASE +
214 		     ACPI_PTR_DIFF(mem_rover, table_ptr));
215 
216 		*table_address = (acpi_physical_address)physical_address;
217 		return_ACPI_STATUS(AE_OK);
218 	}
219 
220 	/* A valid RSDP was not found */
221 
222 	ACPI_BIOS_ERROR((AE_INFO, "A valid RSDP was not found"));
223 	return_ACPI_STATUS(AE_NOT_FOUND);
224 }
225 
226 ACPI_EXPORT_SYMBOL_INIT(acpi_find_root_pointer)
227 
228 /*******************************************************************************
229  *
230  * FUNCTION:    acpi_tb_scan_memory_for_rsdp
231  *
232  * PARAMETERS:  start_address       - Starting pointer for search
233  *              length              - Maximum length to search
234  *
235  * RETURN:      Pointer to the RSDP if found, otherwise NULL.
236  *
237  * DESCRIPTION: Search a block of memory for the RSDP signature
238  *
239  ******************************************************************************/
240 u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length)
241 {
242 	acpi_status status;
243 	u8 *mem_rover;
244 	u8 *end_address;
245 
246 	ACPI_FUNCTION_TRACE(tb_scan_memory_for_rsdp);
247 
248 	end_address = start_address + length;
249 
250 	/* Search from given start address for the requested length */
251 
252 	for (mem_rover = start_address; mem_rover < end_address;
253 	     mem_rover += ACPI_RSDP_SCAN_STEP) {
254 
255 		/* The RSDP signature and checksum must both be correct */
256 
257 		status =
258 		    acpi_tb_validate_rsdp(ACPI_CAST_PTR
259 					  (struct acpi_table_rsdp, mem_rover));
260 		if (ACPI_SUCCESS(status)) {
261 
262 			/* Sig and checksum valid, we have found a real RSDP */
263 
264 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
265 					  "RSDP located at physical address %p\n",
266 					  mem_rover));
267 			return_PTR(mem_rover);
268 		}
269 
270 		/* No sig match or bad checksum, keep searching */
271 	}
272 
273 	/* Searched entire block, no RSDP was found */
274 
275 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
276 			  "Searched entire block from %p, valid RSDP was not found\n",
277 			  start_address));
278 	return_PTR(NULL);
279 }
280