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(buffer: (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(buffer: (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(where: (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(logical_address: 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(where: (acpi_physical_address) |
161 | physical_address, |
162 | length: 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(start_address: table_ptr, length: ebda_window_size); |
173 | acpi_os_unmap_memory(logical_address: table_ptr, size: 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(where: (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(start_address: table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); |
206 | acpi_os_unmap_memory(logical_address: 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 | |