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 - 2021, 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  ******************************************************************************/
acpi_tb_get_rsdp_length(struct acpi_table_rsdp * rsdp)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 
acpi_tb_validate_rsdp(struct acpi_table_rsdp * rsdp)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_tb_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_tb_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
acpi_find_root_pointer(acpi_physical_address * table_address)112 acpi_find_root_pointer(acpi_physical_address *table_address)
113 {
114 	u8 *table_ptr;
115 	u8 *mem_rover;
116 	u32 physical_address;
117 
118 	ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
119 
120 	/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
121 
122 	table_ptr = acpi_os_map_memory((acpi_physical_address)
123 				       ACPI_EBDA_PTR_LOCATION,
124 				       ACPI_EBDA_PTR_LENGTH);
125 	if (!table_ptr) {
126 		ACPI_ERROR((AE_INFO,
127 			    "Could not map memory at 0x%8.8X for length %u",
128 			    ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
129 
130 		return_ACPI_STATUS(AE_NO_MEMORY);
131 	}
132 
133 	ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
134 
135 	/* Convert segment part to physical address */
136 
137 	physical_address <<= 4;
138 	acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
139 
140 	/* EBDA present? */
141 
142 	if (physical_address > 0x400) {
143 		/*
144 		 * 1b) Search EBDA paragraphs (EBDA is required to be a
145 		 *     minimum of 1K length)
146 		 */
147 		table_ptr = acpi_os_map_memory((acpi_physical_address)
148 					       physical_address,
149 					       ACPI_EBDA_WINDOW_SIZE);
150 		if (!table_ptr) {
151 			ACPI_ERROR((AE_INFO,
152 				    "Could not map memory at 0x%8.8X for length %u",
153 				    physical_address, ACPI_EBDA_WINDOW_SIZE));
154 
155 			return_ACPI_STATUS(AE_NO_MEMORY);
156 		}
157 
158 		mem_rover =
159 		    acpi_tb_scan_memory_for_rsdp(table_ptr,
160 						 ACPI_EBDA_WINDOW_SIZE);
161 		acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
162 
163 		if (mem_rover) {
164 
165 			/* Return the physical address */
166 
167 			physical_address +=
168 			    (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
169 
170 			*table_address =
171 			    (acpi_physical_address)physical_address;
172 			return_ACPI_STATUS(AE_OK);
173 		}
174 	}
175 
176 	/*
177 	 * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
178 	 */
179 	table_ptr = acpi_os_map_memory((acpi_physical_address)
180 				       ACPI_HI_RSDP_WINDOW_BASE,
181 				       ACPI_HI_RSDP_WINDOW_SIZE);
182 
183 	if (!table_ptr) {
184 		ACPI_ERROR((AE_INFO,
185 			    "Could not map memory at 0x%8.8X for length %u",
186 			    ACPI_HI_RSDP_WINDOW_BASE,
187 			    ACPI_HI_RSDP_WINDOW_SIZE));
188 
189 		return_ACPI_STATUS(AE_NO_MEMORY);
190 	}
191 
192 	mem_rover =
193 	    acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
194 	acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
195 
196 	if (mem_rover) {
197 
198 		/* Return the physical address */
199 
200 		physical_address = (u32)
201 		    (ACPI_HI_RSDP_WINDOW_BASE +
202 		     ACPI_PTR_DIFF(mem_rover, table_ptr));
203 
204 		*table_address = (acpi_physical_address)physical_address;
205 		return_ACPI_STATUS(AE_OK);
206 	}
207 
208 	/* A valid RSDP was not found */
209 
210 	ACPI_BIOS_ERROR((AE_INFO, "A valid RSDP was not found"));
211 	return_ACPI_STATUS(AE_NOT_FOUND);
212 }
213 
ACPI_EXPORT_SYMBOL_INIT(acpi_find_root_pointer)214 ACPI_EXPORT_SYMBOL_INIT(acpi_find_root_pointer)
215 
216 /*******************************************************************************
217  *
218  * FUNCTION:    acpi_tb_scan_memory_for_rsdp
219  *
220  * PARAMETERS:  start_address       - Starting pointer for search
221  *              length              - Maximum length to search
222  *
223  * RETURN:      Pointer to the RSDP if found, otherwise NULL.
224  *
225  * DESCRIPTION: Search a block of memory for the RSDP signature
226  *
227  ******************************************************************************/
228 u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length)
229 {
230 	acpi_status status;
231 	u8 *mem_rover;
232 	u8 *end_address;
233 
234 	ACPI_FUNCTION_TRACE(tb_scan_memory_for_rsdp);
235 
236 	end_address = start_address + length;
237 
238 	/* Search from given start address for the requested length */
239 
240 	for (mem_rover = start_address; mem_rover < end_address;
241 	     mem_rover += ACPI_RSDP_SCAN_STEP) {
242 
243 		/* The RSDP signature and checksum must both be correct */
244 
245 		status =
246 		    acpi_tb_validate_rsdp(ACPI_CAST_PTR
247 					  (struct acpi_table_rsdp, mem_rover));
248 		if (ACPI_SUCCESS(status)) {
249 
250 			/* Sig and checksum valid, we have found a real RSDP */
251 
252 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
253 					  "RSDP located at physical address %p\n",
254 					  mem_rover));
255 			return_PTR(mem_rover);
256 		}
257 
258 		/* No sig match or bad checksum, keep searching */
259 	}
260 
261 	/* Searched entire block, no RSDP was found */
262 
263 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
264 			  "Searched entire block from %p, valid RSDP was not found\n",
265 			  start_address));
266 	return_PTR(NULL);
267 }
268