diff options
author | Bob Moore <robert.moore@intel.com> | 2007-02-02 11:48:18 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-02-02 21:14:21 -0500 |
commit | f3d2e7865c816258c699ff965768e46b50d536d3 (patch) | |
tree | 83d21269e506109275b77d3ed161883bba8a39cf /drivers/acpi/tables/tbutils.c | |
parent | 2e42005bcdb4f63bed1cea7f537a5534d4bd7a57 (diff) |
ACPICA: Implement simplified Table Manager
The Table Manager component has been completely
redesigned and reimplemented. The new design is much
simpler, and reduces the overall code and data size of
the kernel-resident ACPICA by approximately 5%. Also,
it is now possible to obtain the ACPI tables very early
during kernel initialization, even before dynamic memory
management is initialized.
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/tables/tbutils.c')
-rw-r--r-- | drivers/acpi/tables/tbutils.c | 600 |
1 files changed, 406 insertions, 194 deletions
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 209a401801e3..3620ac5f8681 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Module Name: tbutils - Table manipulation utilities | 3 | * Module Name: tbutils - table utilities |
4 | * | 4 | * |
5 | *****************************************************************************/ | 5 | *****************************************************************************/ |
6 | 6 | ||
@@ -48,295 +48,507 @@ | |||
48 | ACPI_MODULE_NAME("tbutils") | 48 | ACPI_MODULE_NAME("tbutils") |
49 | 49 | ||
50 | /* Local prototypes */ | 50 | /* Local prototypes */ |
51 | #ifdef ACPI_OBSOLETE_FUNCTIONS | 51 | static void acpi_tb_parse_fadt(struct acpi_table_fadt *fadt, u8 flags); |
52 | acpi_status | 52 | |
53 | acpi_tb_handle_to_object(u16 table_id, struct acpi_table_desc **table_desc); | 53 | static void inline |
54 | #endif | 54 | acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, |
55 | u8 bit_width, acpi_physical_address address); | ||
55 | 56 | ||
56 | /******************************************************************************* | 57 | /******************************************************************************* |
57 | * | 58 | * |
58 | * FUNCTION: acpi_tb_is_table_installed | 59 | * FUNCTION: acpi_tb_print_table_header |
59 | * | 60 | * |
60 | * PARAMETERS: new_table_desc - Descriptor for new table being installed | 61 | * PARAMETERS: Address - Table physical address |
62 | * Header - Table header | ||
61 | * | 63 | * |
62 | * RETURN: Status - AE_ALREADY_EXISTS if the table is already installed | 64 | * RETURN: None |
63 | * | 65 | * |
64 | * DESCRIPTION: Determine if an ACPI table is already installed | 66 | * DESCRIPTION: Print an ACPI table header |
65 | * | ||
66 | * MUTEX: Table data structures should be locked | ||
67 | * | 67 | * |
68 | ******************************************************************************/ | 68 | ******************************************************************************/ |
69 | 69 | ||
70 | acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc) | 70 | void |
71 | acpi_tb_print_table_header(acpi_physical_address address, | ||
72 | struct acpi_table_header *header) | ||
71 | { | 73 | { |
72 | struct acpi_table_desc *table_desc; | ||
73 | |||
74 | ACPI_FUNCTION_TRACE(tb_is_table_installed); | ||
75 | |||
76 | /* Get the list descriptor and first table descriptor */ | ||
77 | |||
78 | table_desc = acpi_gbl_table_lists[new_table_desc->type].next; | ||
79 | |||
80 | /* Examine all installed tables of this type */ | ||
81 | |||
82 | while (table_desc) { | ||
83 | /* | ||
84 | * If the table lengths match, perform a full bytewise compare. This | ||
85 | * means that we will allow tables with duplicate oem_table_id(s), as | ||
86 | * long as the tables are different in some way. | ||
87 | * | ||
88 | * Checking if the table has been loaded into the namespace means that | ||
89 | * we don't check for duplicate tables during the initial installation | ||
90 | * of tables within the RSDT/XSDT. | ||
91 | */ | ||
92 | if ((table_desc->loaded_into_namespace) && | ||
93 | (table_desc->pointer->length == | ||
94 | new_table_desc->pointer->length) | ||
95 | && | ||
96 | (!ACPI_MEMCMP | ||
97 | (table_desc->pointer, new_table_desc->pointer, | ||
98 | new_table_desc->pointer->length))) { | ||
99 | |||
100 | /* Match: this table is already installed */ | ||
101 | |||
102 | ACPI_DEBUG_PRINT((ACPI_DB_TABLES, | ||
103 | "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n", | ||
104 | new_table_desc->pointer->signature, | ||
105 | new_table_desc->pointer->revision, | ||
106 | new_table_desc->pointer-> | ||
107 | oem_table_id)); | ||
108 | |||
109 | new_table_desc->owner_id = table_desc->owner_id; | ||
110 | new_table_desc->installed_desc = table_desc; | ||
111 | |||
112 | return_ACPI_STATUS(AE_ALREADY_EXISTS); | ||
113 | } | ||
114 | |||
115 | /* Get next table on the list */ | ||
116 | 74 | ||
117 | table_desc = table_desc->next; | 75 | ACPI_INFO((AE_INFO, |
118 | } | 76 | "%4.4s @ 0x%p Length 0x%04X (v%3.3d %6.6s %8.8s 0x%08X %4.4s 0x%08X)", |
119 | 77 | header->signature, ACPI_CAST_PTR(void, address), | |
120 | return_ACPI_STATUS(AE_OK); | 78 | header->length, header->revision, header->oem_id, |
79 | header->oem_table_id, header->oem_revision, | ||
80 | header->asl_compiler_id, header->asl_compiler_revision)); | ||
121 | } | 81 | } |
122 | 82 | ||
123 | /******************************************************************************* | 83 | /******************************************************************************* |
124 | * | 84 | * |
125 | * FUNCTION: acpi_tb_validate_table_header | 85 | * FUNCTION: acpi_tb_init_generic_address |
126 | * | ||
127 | * PARAMETERS: table_header - Logical pointer to the table | ||
128 | * | 86 | * |
129 | * RETURN: Status | 87 | * PARAMETERS: new_gas_struct - GAS struct to be initialized |
88 | * bit_width - Width of this register | ||
89 | * Address - Address of the register | ||
130 | * | 90 | * |
131 | * DESCRIPTION: Check an ACPI table header for validity | 91 | * RETURN: None |
132 | * | 92 | * |
133 | * NOTE: Table pointers are validated as follows: | 93 | * DESCRIPTION: Initialize a GAS structure. |
134 | * 1) Table pointer must point to valid physical memory | ||
135 | * 2) Signature must be 4 ASCII chars, even if we don't recognize the | ||
136 | * name | ||
137 | * 3) Table must be readable for length specified in the header | ||
138 | * 4) Table checksum must be valid (with the exception of the FACS | ||
139 | * which has no checksum because it contains variable fields) | ||
140 | * | 94 | * |
141 | ******************************************************************************/ | 95 | ******************************************************************************/ |
142 | 96 | ||
143 | acpi_status | 97 | static void inline |
144 | acpi_tb_validate_table_header(struct acpi_table_header *table_header) | 98 | acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, |
99 | u8 bit_width, acpi_physical_address address) | ||
145 | { | 100 | { |
146 | acpi_name signature; | ||
147 | |||
148 | ACPI_FUNCTION_ENTRY(); | ||
149 | |||
150 | /* Verify that this is a valid address */ | ||
151 | |||
152 | if (!acpi_os_readable(table_header, sizeof(struct acpi_table_header))) { | ||
153 | ACPI_ERROR((AE_INFO, | ||
154 | "Cannot read table header at %p", table_header)); | ||
155 | |||
156 | return (AE_BAD_ADDRESS); | ||
157 | } | ||
158 | |||
159 | /* Ensure that the signature is 4 ASCII characters */ | ||
160 | |||
161 | ACPI_MOVE_32_TO_32(&signature, table_header->signature); | ||
162 | if (!acpi_ut_valid_acpi_name(signature)) { | ||
163 | ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X", | ||
164 | signature)); | ||
165 | 101 | ||
166 | ACPI_DUMP_BUFFER(table_header, | 102 | ACPI_STORE_ADDRESS(new_gas_struct->address, address); |
167 | sizeof(struct acpi_table_header)); | 103 | new_gas_struct->space_id = ACPI_ADR_SPACE_SYSTEM_IO; |
168 | return (AE_BAD_SIGNATURE); | 104 | new_gas_struct->bit_width = bit_width; |
169 | } | 105 | new_gas_struct->bit_offset = 0; |
170 | 106 | new_gas_struct->access_width = 0; | |
171 | /* Validate the table length */ | ||
172 | |||
173 | if (table_header->length < sizeof(struct acpi_table_header)) { | ||
174 | ACPI_ERROR((AE_INFO, | ||
175 | "Invalid length 0x%X in table with signature %4.4s", | ||
176 | (u32) table_header->length, | ||
177 | ACPI_CAST_PTR(char, &signature))); | ||
178 | |||
179 | ACPI_DUMP_BUFFER(table_header, | ||
180 | sizeof(struct acpi_table_header)); | ||
181 | return (AE_BAD_HEADER); | ||
182 | } | ||
183 | |||
184 | return (AE_OK); | ||
185 | } | 107 | } |
186 | 108 | ||
187 | /******************************************************************************* | 109 | /******************************************************************************* |
188 | * | 110 | * |
189 | * FUNCTION: acpi_tb_sum_table | 111 | * FUNCTION: acpi_tb_checksum |
190 | * | 112 | * |
191 | * PARAMETERS: Buffer - Buffer to sum | 113 | * PARAMETERS: Buffer - Pointer to memory region to be checked |
192 | * Length - Size of the buffer | 114 | * Length - Length of this memory region |
193 | * | 115 | * |
194 | * RETURN: 8 bit sum of buffer | 116 | * RETURN: Checksum (u8) |
195 | * | 117 | * |
196 | * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it. | 118 | * DESCRIPTION: Calculates circular checksum of memory region. |
197 | * | 119 | * |
198 | ******************************************************************************/ | 120 | ******************************************************************************/ |
199 | 121 | ||
200 | u8 acpi_tb_sum_table(void *buffer, u32 length) | 122 | u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length) |
201 | { | 123 | { |
202 | acpi_native_uint i; | ||
203 | u8 sum = 0; | 124 | u8 sum = 0; |
125 | u8 *end = buffer + length; | ||
204 | 126 | ||
205 | if (!buffer || !length) { | 127 | while (buffer < end) { |
206 | return (0); | 128 | sum = (u8) (sum + *(buffer++)); |
207 | } | 129 | } |
208 | 130 | ||
209 | for (i = 0; i < length; i++) { | 131 | return sum; |
210 | sum = (u8) (sum + ((u8 *) buffer)[i]); | ||
211 | } | ||
212 | return (sum); | ||
213 | } | 132 | } |
214 | 133 | ||
215 | /******************************************************************************* | 134 | /******************************************************************************* |
216 | * | 135 | * |
217 | * FUNCTION: acpi_tb_generate_checksum | 136 | * FUNCTION: acpi_tb_convert_fadt |
218 | * | 137 | * |
219 | * PARAMETERS: Table - Pointer to a valid ACPI table (with a | 138 | * PARAMETERS: Fadt - FADT table to be converted |
220 | * standard ACPI header) | ||
221 | * | 139 | * |
222 | * RETURN: 8 bit checksum of buffer | 140 | * RETURN: None |
223 | * | 141 | * |
224 | * DESCRIPTION: Computes an 8 bit checksum of the table. | 142 | * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local |
143 | * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply | ||
144 | * copied to the local FADT. The ACPI CA software uses this | ||
145 | * local FADT. Thus a significant amount of special #ifdef | ||
146 | * type codeing is saved. | ||
225 | * | 147 | * |
226 | ******************************************************************************/ | 148 | ******************************************************************************/ |
227 | 149 | ||
228 | u8 acpi_tb_generate_checksum(struct acpi_table_header * table) | 150 | void acpi_tb_convert_fadt(struct acpi_table_fadt *fadt) |
229 | { | 151 | { |
230 | u8 checksum; | ||
231 | |||
232 | /* Sum the entire table as-is */ | ||
233 | 152 | ||
234 | checksum = acpi_tb_sum_table(table, table->length); | 153 | /* |
154 | * Convert table pointers to 64-bit fields | ||
155 | */ | ||
156 | if (!acpi_gbl_FADT.Xfacs) { | ||
157 | acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; | ||
158 | } | ||
235 | 159 | ||
236 | /* Subtract off the existing checksum value in the table */ | 160 | if (!acpi_gbl_FADT.Xdsdt) { |
161 | acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; | ||
162 | } | ||
237 | 163 | ||
238 | checksum = (u8) (checksum - table->checksum); | 164 | /* |
165 | * Convert the V1.0 block addresses to V2.0 GAS structures | ||
166 | */ | ||
167 | acpi_tb_init_generic_address(&acpi_gbl_FADT.xpm1a_event_block, | ||
168 | acpi_gbl_FADT.pm1_event_length, | ||
169 | (acpi_physical_address) acpi_gbl_FADT. | ||
170 | pm1a_event_block); | ||
171 | acpi_tb_init_generic_address(&acpi_gbl_FADT.xpm1b_event_block, | ||
172 | acpi_gbl_FADT.pm1_event_length, | ||
173 | (acpi_physical_address) acpi_gbl_FADT. | ||
174 | pm1b_event_block); | ||
175 | acpi_tb_init_generic_address(&acpi_gbl_FADT.xpm1a_control_block, | ||
176 | acpi_gbl_FADT.pm1_control_length, | ||
177 | (acpi_physical_address) acpi_gbl_FADT. | ||
178 | pm1a_control_block); | ||
179 | acpi_tb_init_generic_address(&acpi_gbl_FADT.xpm1b_control_block, | ||
180 | acpi_gbl_FADT.pm1_control_length, | ||
181 | (acpi_physical_address) acpi_gbl_FADT. | ||
182 | pm1b_control_block); | ||
183 | acpi_tb_init_generic_address(&acpi_gbl_FADT.xpm2_control_block, | ||
184 | acpi_gbl_FADT.pm2_control_length, | ||
185 | (acpi_physical_address) acpi_gbl_FADT. | ||
186 | pm2_control_block); | ||
187 | acpi_tb_init_generic_address(&acpi_gbl_FADT.xpm_timer_block, | ||
188 | acpi_gbl_FADT.pm_timer_length, | ||
189 | (acpi_physical_address) acpi_gbl_FADT. | ||
190 | pm_timer_block); | ||
191 | acpi_tb_init_generic_address(&acpi_gbl_FADT.xgpe0_block, 0, | ||
192 | (acpi_physical_address) acpi_gbl_FADT. | ||
193 | gpe0_block); | ||
194 | acpi_tb_init_generic_address(&acpi_gbl_FADT.xgpe1_block, 0, | ||
195 | (acpi_physical_address) acpi_gbl_FADT. | ||
196 | gpe1_block); | ||
197 | |||
198 | /* | ||
199 | * Create separate GAS structs for the PM1 Enable registers | ||
200 | */ | ||
201 | acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, | ||
202 | (u8) ACPI_DIV_2(acpi_gbl_FADT. | ||
203 | pm1_event_length), | ||
204 | (acpi_physical_address) | ||
205 | (acpi_gbl_FADT.xpm1a_event_block.address + | ||
206 | ACPI_DIV_2(acpi_gbl_FADT. | ||
207 | pm1_event_length))); | ||
208 | |||
209 | /* | ||
210 | * PM1B is optional; leave null if not present | ||
211 | */ | ||
212 | if (acpi_gbl_FADT.xpm1b_event_block.address) { | ||
213 | acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, | ||
214 | (u8) ACPI_DIV_2(acpi_gbl_FADT. | ||
215 | pm1_event_length), | ||
216 | (acpi_physical_address) | ||
217 | (acpi_gbl_FADT.xpm1b_event_block. | ||
218 | address + | ||
219 | ACPI_DIV_2(acpi_gbl_FADT. | ||
220 | pm1_event_length))); | ||
221 | } | ||
239 | 222 | ||
240 | /* Compute the final checksum */ | 223 | /* Global FADT is the new common V2.0 FADT */ |
241 | 224 | ||
242 | checksum = (u8) (0 - checksum); | 225 | acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); |
243 | return (checksum); | ||
244 | } | 226 | } |
245 | 227 | ||
246 | /******************************************************************************* | 228 | /******************************************************************************* |
247 | * | 229 | * |
248 | * FUNCTION: acpi_tb_set_checksum | 230 | * FUNCTION: acpi_tb_parse_fadt |
249 | * | 231 | * |
250 | * PARAMETERS: Table - Pointer to a valid ACPI table (with a | 232 | * PARAMETERS: Fadt - Pointer to FADT table |
251 | * standard ACPI header) | 233 | * Flags - Flags |
252 | * | 234 | * |
253 | * RETURN: None. Sets the table checksum field | 235 | * RETURN: none |
254 | * | 236 | * |
255 | * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the | 237 | * DESCRIPTION: This function is called to initialise the FADT, DSDT and FACS |
256 | * checksum into the table header. | 238 | * tables (FADT contains the addresses of the DSDT and FACS) |
257 | * | 239 | * |
258 | ******************************************************************************/ | 240 | ******************************************************************************/ |
259 | 241 | ||
260 | void acpi_tb_set_checksum(struct acpi_table_header *table) | 242 | static void acpi_tb_parse_fadt(struct acpi_table_fadt *fadt, u8 flags) |
261 | { | 243 | { |
244 | acpi_physical_address dsdt_address = | ||
245 | (acpi_physical_address) fadt->Xdsdt; | ||
246 | acpi_physical_address facs_address = | ||
247 | (acpi_physical_address) fadt->Xfacs; | ||
248 | struct acpi_table_header *table; | ||
249 | |||
250 | if (!dsdt_address) { | ||
251 | goto no_dsdt; | ||
252 | } | ||
253 | |||
254 | table = | ||
255 | acpi_os_map_memory(dsdt_address, sizeof(struct acpi_table_header)); | ||
256 | if (!table) { | ||
257 | goto no_dsdt; | ||
258 | } | ||
259 | |||
260 | /* Initialize the DSDT table */ | ||
261 | |||
262 | ACPI_MOVE_32_TO_32(& | ||
263 | (acpi_gbl_root_table_list. | ||
264 | tables[ACPI_TABLE_INDEX_DSDT].signature), | ||
265 | ACPI_SIG_DSDT); | ||
266 | |||
267 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].address = | ||
268 | dsdt_address; | ||
269 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length = | ||
270 | table->length; | ||
271 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags = flags; | ||
272 | |||
273 | acpi_tb_print_table_header(dsdt_address, table); | ||
274 | |||
275 | /* Global integer width is based upon revision of the DSDT */ | ||
276 | |||
277 | acpi_ut_set_integer_width(table->revision); | ||
278 | acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); | ||
279 | |||
280 | no_dsdt: | ||
281 | if (!facs_address) { | ||
282 | return; | ||
283 | } | ||
262 | 284 | ||
263 | table->checksum = acpi_tb_generate_checksum(table); | 285 | table = |
286 | acpi_os_map_memory(facs_address, sizeof(struct acpi_table_header)); | ||
287 | if (!table) { | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | /* Initialize the FACS table */ | ||
292 | |||
293 | ACPI_MOVE_32_TO_32(& | ||
294 | (acpi_gbl_root_table_list. | ||
295 | tables[ACPI_TABLE_INDEX_FACS].signature), | ||
296 | ACPI_SIG_FACS); | ||
297 | |||
298 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_FACS].address = | ||
299 | facs_address; | ||
300 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_FACS].length = | ||
301 | table->length; | ||
302 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_FACS].flags = flags; | ||
303 | |||
304 | ACPI_INFO((AE_INFO, "%4.4s @ 0x%p", | ||
305 | table->signature, ACPI_CAST_PTR(void, facs_address))); | ||
306 | |||
307 | acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); | ||
264 | } | 308 | } |
265 | 309 | ||
266 | /******************************************************************************* | 310 | /******************************************************************************* |
267 | * | 311 | * |
268 | * FUNCTION: acpi_tb_verify_table_checksum | 312 | * FUNCTION: acpi_tb_parse_root_table |
269 | * | 313 | * |
270 | * PARAMETERS: *table_header - ACPI table to verify | 314 | * PARAMETERS: Rsdp - Pointer to the RSDP |
315 | * Flags - Flags | ||
316 | * | ||
317 | * RETURN: Status | ||
271 | * | 318 | * |
272 | * RETURN: 8 bit checksum of table | 319 | * DESCRIPTION: This function is called to parse the Root System Description |
320 | * Table (RSDT or XSDT) | ||
273 | * | 321 | * |
274 | * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares | 322 | * NOTE: Tables are mapped (not copied) for efficiency. The FACS must |
275 | * it to the existing checksum value. | 323 | * be mapped and cannot be copied because it contains the actual |
324 | * memory location of the ACPI Global Lock. | ||
276 | * | 325 | * |
277 | ******************************************************************************/ | 326 | ******************************************************************************/ |
278 | 327 | ||
279 | acpi_status | 328 | acpi_status acpi_tb_parse_root_table(struct acpi_table_rsdp *rsdp, u8 flags) |
280 | acpi_tb_verify_table_checksum(struct acpi_table_header *table_header) | ||
281 | { | 329 | { |
330 | struct acpi_table_header *table; | ||
331 | acpi_physical_address address; | ||
332 | u32 length; | ||
333 | u8 *table_entry; | ||
334 | acpi_native_uint i; | ||
335 | acpi_native_uint pointer_size; | ||
336 | u32 table_count; | ||
282 | u8 checksum; | 337 | u8 checksum; |
338 | acpi_status status; | ||
339 | |||
340 | ACPI_FUNCTION_TRACE(tb_parse_root_table); | ||
341 | |||
342 | /* Differentiate between RSDT and XSDT root tables */ | ||
343 | |||
344 | if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { | ||
345 | /* | ||
346 | * Root table is an XSDT (64-bit physical addresses). We must use the | ||
347 | * XSDT if the revision is > 1 and the XSDT pointer is present, as per | ||
348 | * the ACPI specification. | ||
349 | */ | ||
350 | address = (acpi_native_uint) rsdp->xsdt_physical_address; | ||
351 | pointer_size = sizeof(u64); | ||
352 | } else { | ||
353 | /* Root table is an RSDT (32-bit physical addresses) */ | ||
354 | |||
355 | address = (acpi_native_uint) rsdp->rsdt_physical_address; | ||
356 | pointer_size = sizeof(u32); | ||
357 | } | ||
283 | 358 | ||
284 | ACPI_FUNCTION_TRACE(tb_verify_table_checksum); | 359 | /* Map the table header to get the full table length */ |
285 | 360 | ||
286 | /* Compute the checksum on the table */ | 361 | table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); |
362 | if (!table) { | ||
363 | return (AE_NO_MEMORY); | ||
364 | } | ||
365 | |||
366 | /* Get the length of the full table, verify length and map entire table */ | ||
367 | |||
368 | length = table->length; | ||
369 | acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); | ||
370 | |||
371 | if (length < sizeof(struct acpi_table_header)) { | ||
372 | ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT", | ||
373 | length)); | ||
374 | return (AE_INVALID_TABLE_LENGTH); | ||
375 | } | ||
376 | |||
377 | table = acpi_os_map_memory(address, length); | ||
378 | if (!table) { | ||
379 | return (AE_NO_MEMORY); | ||
380 | } | ||
381 | |||
382 | /* Validate the root table checksum */ | ||
383 | |||
384 | checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length); | ||
385 | #if (ACPI_CHECKSUM_ABORT) | ||
386 | |||
387 | if (checksum) { | ||
388 | acpi_os_unmap_memory(table, length); | ||
389 | return (AE_BAD_CHECKSUM); | ||
390 | } | ||
391 | #endif | ||
392 | |||
393 | acpi_tb_print_table_header(address, table); | ||
394 | |||
395 | /* Calculate the number of tables described in the root table */ | ||
396 | |||
397 | table_count = | ||
398 | (table->length - sizeof(struct acpi_table_header)) / pointer_size; | ||
399 | |||
400 | /* Setup loop */ | ||
287 | 401 | ||
288 | checksum = acpi_tb_generate_checksum(table_header); | 402 | table_entry = |
403 | ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); | ||
404 | acpi_gbl_root_table_list.count = 2; | ||
289 | 405 | ||
290 | /* Checksum ok? */ | 406 | /* |
407 | * Initialize the ACPI table entries | ||
408 | * First two entries in the table array are reserved for the DSDT and FACS | ||
409 | */ | ||
410 | for (i = 0; i < table_count; ++i, table_entry += pointer_size) { | ||
291 | 411 | ||
292 | if (checksum == table_header->checksum) { | 412 | /* Ensure there is room for another table entry */ |
293 | return_ACPI_STATUS(AE_OK); | 413 | |
414 | if (acpi_gbl_root_table_list.count >= | ||
415 | acpi_gbl_root_table_list.size) { | ||
416 | status = acpi_tb_resize_root_table_list(); | ||
417 | if (ACPI_FAILURE(status)) { | ||
418 | ACPI_WARNING((AE_INFO, | ||
419 | "Truncating %u table entries!", | ||
420 | (unsigned) | ||
421 | (acpi_gbl_root_table_list.size - | ||
422 | acpi_gbl_root_table_list. | ||
423 | count))); | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /* Get the physical address (32-bit for RSDT, 64-bit for XSDT) */ | ||
429 | |||
430 | if (pointer_size == sizeof(u32)) { | ||
431 | acpi_gbl_root_table_list. | ||
432 | tables[acpi_gbl_root_table_list.count].address = | ||
433 | (acpi_physical_address) (*ACPI_CAST_PTR | ||
434 | (u32, table_entry)); | ||
435 | } else { | ||
436 | acpi_gbl_root_table_list. | ||
437 | tables[acpi_gbl_root_table_list.count].address = | ||
438 | (acpi_physical_address) (*ACPI_CAST_PTR | ||
439 | (u64, table_entry)); | ||
440 | } | ||
441 | |||
442 | acpi_gbl_root_table_list.count++; | ||
294 | } | 443 | } |
295 | 444 | ||
296 | ACPI_WARNING((AE_INFO, | 445 | /* |
297 | "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X", | 446 | * It is not possible to map more than one entry in some environments, |
298 | table_header->signature, table_header->checksum, | 447 | * so unmap the root table here before mapping other tables |
299 | checksum)); | 448 | */ |
449 | acpi_os_unmap_memory(table, length); | ||
450 | |||
451 | /* Initialize all tables other than the DSDT and FACS */ | ||
452 | |||
453 | for (i = 2; i < acpi_gbl_root_table_list.count; i++) { | ||
454 | address = acpi_gbl_root_table_list.tables[i].address; | ||
455 | length = sizeof(struct acpi_table_header); | ||
456 | |||
457 | table = acpi_os_map_memory(address, length); | ||
458 | if (!table) { | ||
459 | continue; | ||
460 | } | ||
461 | |||
462 | acpi_gbl_root_table_list.tables[i].length = table->length; | ||
463 | acpi_gbl_root_table_list.tables[i].flags = flags; | ||
464 | |||
465 | ACPI_MOVE_32_TO_32(& | ||
466 | (acpi_gbl_root_table_list.tables[i]. | ||
467 | signature), table->signature); | ||
468 | |||
469 | acpi_tb_print_table_header(address, table); | ||
470 | |||
471 | /* | ||
472 | * Special case for the FADT because of multiple versions - | ||
473 | * get a local copy and convert to common format | ||
474 | */ | ||
475 | if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_FADT)) { | ||
476 | acpi_os_unmap_memory(table, length); | ||
477 | length = table->length; | ||
478 | |||
479 | table = acpi_os_map_memory(address, length); | ||
480 | if (!table) { | ||
481 | continue; | ||
482 | } | ||
483 | |||
484 | /* Copy the entire FADT locally */ | ||
485 | |||
486 | ACPI_MEMCPY(&acpi_gbl_FADT, table, | ||
487 | ACPI_MIN(table->length, | ||
488 | sizeof(struct acpi_table_fadt))); | ||
489 | |||
490 | /* Small table means old revision, convert to new */ | ||
491 | |||
492 | if (table->length < sizeof(struct acpi_table_fadt)) { | ||
493 | acpi_tb_convert_fadt(ACPI_CAST_PTR | ||
494 | (struct acpi_table_fadt, | ||
495 | table)); | ||
496 | } | ||
497 | |||
498 | /* Unmap original FADT */ | ||
300 | 499 | ||
301 | return_ACPI_STATUS(AE_BAD_CHECKSUM); | 500 | acpi_os_unmap_memory(table, length); |
501 | acpi_tb_parse_fadt(&acpi_gbl_FADT, flags); | ||
502 | } else { | ||
503 | acpi_os_unmap_memory(table, length); | ||
504 | } | ||
505 | } | ||
506 | |||
507 | return_ACPI_STATUS(AE_OK); | ||
302 | } | 508 | } |
303 | 509 | ||
304 | #ifdef ACPI_OBSOLETE_FUNCTIONS | 510 | /****************************************************************************** |
305 | /******************************************************************************* | ||
306 | * | 511 | * |
307 | * FUNCTION: acpi_tb_handle_to_object | 512 | * FUNCTION: acpi_tb_map |
308 | * | 513 | * |
309 | * PARAMETERS: table_id - Id for which the function is searching | 514 | * PARAMETERS: Address - Address to be mapped |
310 | * table_desc - Pointer to return the matching table | 515 | * Length - Length to be mapped |
311 | * descriptor. | 516 | * Flags - Logical or physical addressing mode |
312 | * | 517 | * |
313 | * RETURN: Search the tables to find one with a matching table_id and | 518 | * RETURN: Pointer to mapped region |
314 | * return a pointer to that table descriptor. | ||
315 | * | 519 | * |
316 | ******************************************************************************/ | 520 | * DESCRIPTION: Maps memory according to flag |
521 | * | ||
522 | *****************************************************************************/ | ||
317 | 523 | ||
318 | acpi_status | 524 | void *acpi_tb_map(acpi_physical_address address, u32 length, u32 flags) |
319 | acpi_tb_handle_to_object(u16 table_id, | ||
320 | struct acpi_table_desc **return_table_desc) | ||
321 | { | 525 | { |
322 | u32 i; | ||
323 | struct acpi_table_desc *table_desc; | ||
324 | 526 | ||
325 | ACPI_FUNCTION_NAME(tb_handle_to_object); | 527 | if (flags == ACPI_TABLE_ORIGIN_MAPPED) { |
528 | return (acpi_os_map_memory(address, length)); | ||
529 | } else { | ||
530 | return (ACPI_CAST_PTR(void, address)); | ||
531 | } | ||
532 | } | ||
326 | 533 | ||
327 | for (i = 0; i < ACPI_TABLE_MAX; i++) { | 534 | /****************************************************************************** |
328 | table_desc = acpi_gbl_table_lists[i].next; | 535 | * |
329 | while (table_desc) { | 536 | * FUNCTION: acpi_tb_unmap |
330 | if (table_desc->table_id == table_id) { | 537 | * |
331 | *return_table_desc = table_desc; | 538 | * PARAMETERS: Pointer - To mapped region |
332 | return (AE_OK); | 539 | * Length - Length to be unmapped |
333 | } | 540 | * Flags - Logical or physical addressing mode |
541 | * | ||
542 | * RETURN: None | ||
543 | * | ||
544 | * DESCRIPTION: Unmaps memory according to flag | ||
545 | * | ||
546 | *****************************************************************************/ | ||
334 | 547 | ||
335 | table_desc = table_desc->next; | 548 | void acpi_tb_unmap(void *pointer, u32 length, u32 flags) |
336 | } | 549 | { |
337 | } | ||
338 | 550 | ||
339 | ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id)); | 551 | if (flags == ACPI_TABLE_ORIGIN_MAPPED) { |
340 | return (AE_BAD_PARAMETER); | 552 | acpi_os_unmap_memory(pointer, length); |
553 | } | ||
341 | } | 554 | } |
342 | #endif | ||