GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / acpi / acpica / tbxfroot.c
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 }