aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/tables/tbfadt.c
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2007-02-02 11:48:20 -0500
committerLen Brown <len.brown@intel.com>2007-02-02 21:14:25 -0500
commitea5d8ebcbb7ca3bcb35a2133805571295f3f06e8 (patch)
treef29ca361fe3e9592898730fcd5e42d9fdff84429 /drivers/acpi/tables/tbfadt.c
parent775d85b6aa33116da8aacad4168c540ce86a1803 (diff)
ACPICA: FADT verification is now table driven.
Disassembler now verifies an input 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/tbfadt.c')
-rw-r--r--drivers/acpi/tables/tbfadt.c289
1 files changed, 153 insertions, 136 deletions
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 62485d32fcd6..8816bab0fe0e 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -49,74 +49,92 @@ ACPI_MODULE_NAME("tbfadt")
49 49
50/* Local prototypes */ 50/* Local prototypes */
51static void inline 51static void inline
52acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, 52acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
53 u8 bit_width, u64 address); 53 u8 bit_width, u64 address);
54 54
55static void acpi_tb_fadt_register_error(char *register_name, u32 value); 55/* Table for conversion of FADT to common internal format and FADT validation */
56 56
57static void acpi_tb_convert_fadt(void); 57typedef struct acpi_fadt_info {
58 58 char *name;
59static void acpi_tb_validate_fadt(void);
60
61/* Table used for conversion of FADT to common format */
62
63typedef struct acpi_fadt_conversion {
64 u8 target; 59 u8 target;
65 u8 source; 60 u8 source;
66 u8 length; 61 u8 length;
62 u8 type;
67 63
68} acpi_fadt_conversion; 64} acpi_fadt_info;
69 65
70static struct acpi_fadt_conversion fadt_conversion_table[] = { 66#define ACPI_FADT_REQUIRED 1
71 {ACPI_FADT_OFFSET(xpm1a_event_block), 67#define ACPI_FADT_SEPARATE_LENGTH 2
68
69static struct acpi_fadt_info fadt_info_table[] = {
70 {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block),
72 ACPI_FADT_OFFSET(pm1a_event_block), 71 ACPI_FADT_OFFSET(pm1a_event_block),
73 ACPI_FADT_OFFSET(pm1_event_length)}, 72 ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED},
74 {ACPI_FADT_OFFSET(xpm1b_event_block), 73
74 {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block),
75 ACPI_FADT_OFFSET(pm1b_event_block), 75 ACPI_FADT_OFFSET(pm1b_event_block),
76 ACPI_FADT_OFFSET(pm1_event_length)}, 76 ACPI_FADT_OFFSET(pm1_event_length), 0},
77 {ACPI_FADT_OFFSET(xpm1a_control_block), 77
78 {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block),
78 ACPI_FADT_OFFSET(pm1a_control_block), 79 ACPI_FADT_OFFSET(pm1a_control_block),
79 ACPI_FADT_OFFSET(pm1_control_length)}, 80 ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED},
80 {ACPI_FADT_OFFSET(xpm1b_control_block), 81
82 {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block),
81 ACPI_FADT_OFFSET(pm1b_control_block), 83 ACPI_FADT_OFFSET(pm1b_control_block),
82 ACPI_FADT_OFFSET(pm1_control_length)}, 84 ACPI_FADT_OFFSET(pm1_control_length), 0},
83 {ACPI_FADT_OFFSET(xpm2_control_block), 85
86 {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block),
84 ACPI_FADT_OFFSET(pm2_control_block), 87 ACPI_FADT_OFFSET(pm2_control_block),
85 ACPI_FADT_OFFSET(pm2_control_length)}, 88 ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH},
86 {ACPI_FADT_OFFSET(xpm_timer_block), ACPI_FADT_OFFSET(pm_timer_block), 89
87 ACPI_FADT_OFFSET(pm_timer_length)}, 90 {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block),
88 {ACPI_FADT_OFFSET(xgpe0_block), ACPI_FADT_OFFSET(gpe0_block), 91 ACPI_FADT_OFFSET(pm_timer_block),
89 ACPI_FADT_OFFSET(gpe0_block_length)}, 92 ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED},
90 {ACPI_FADT_OFFSET(xgpe1_block), ACPI_FADT_OFFSET(gpe1_block), 93
91 ACPI_FADT_OFFSET(gpe1_block_length)} 94 {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block),
95 ACPI_FADT_OFFSET(gpe0_block),
96 ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH},
97
98 {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block),
99 ACPI_FADT_OFFSET(gpe1_block),
100 ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH}
92}; 101};
93 102
94#define ACPI_FADT_CONVERSION_ENTRIES (sizeof (fadt_conversion_table) / sizeof (struct acpi_fadt_conversion)) 103#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
95 104
96/******************************************************************************* 105/*******************************************************************************
97 * 106 *
98 * FUNCTION: acpi_tb_init_generic_address 107 * FUNCTION: acpi_tb_init_generic_address
99 * 108 *
100 * PARAMETERS: new_gas_struct - GAS struct to be initialized 109 * PARAMETERS: generic_address - GAS struct to be initialized
101 * bit_width - Width of this register 110 * bit_width - Width of this register
102 * Address - Address of the register 111 * Address - Address of the register
103 * 112 *
104 * RETURN: None 113 * RETURN: None
105 * 114 *
106 * DESCRIPTION: Initialize a GAS structure. 115 * DESCRIPTION: Initialize a Generic Address Structure (GAS)
116 * See the ACPI specification for a full description and
117 * definition of this structure.
107 * 118 *
108 ******************************************************************************/ 119 ******************************************************************************/
109 120
110static void inline 121static void inline
111acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, 122acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
112 u8 bit_width, u64 address) 123 u8 bit_width, u64 address)
113{ 124{
114 125
115 ACPI_MOVE_64_TO_64(&new_gas_struct->address, &address); 126 /*
116 new_gas_struct->space_id = ACPI_ADR_SPACE_SYSTEM_IO; 127 * The 64-bit Address field is non-aligned in the byte packed
117 new_gas_struct->bit_width = bit_width; 128 * GAS struct.
118 new_gas_struct->bit_offset = 0; 129 */
119 new_gas_struct->access_width = 0; 130 ACPI_MOVE_64_TO_64(&generic_address->address, &address);
131
132 /* All other fields are byte-wide */
133
134 generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
135 generic_address->bit_width = bit_width;
136 generic_address->bit_offset = 0;
137 generic_address->access_width = 0;
120} 138}
121 139
122/******************************************************************************* 140/*******************************************************************************
@@ -139,8 +157,8 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
139 struct acpi_table_header *table; 157 struct acpi_table_header *table;
140 158
141 /* 159 /*
142 * Special case for the FADT because of multiple versions and the fact 160 * The FADT has multiple versions with different lengths,
143 * that it contains pointers to both the DSDT and FACS tables. 161 * and it contains pointers to both the DSDT and FACS tables.
144 * 162 *
145 * Get a local copy of the FADT and convert it to a common format 163 * Get a local copy of the FADT and convert it to a common format
146 * Map entire FADT, assumed to be smaller than one page. 164 * Map entire FADT, assumed to be smaller than one page.
@@ -160,29 +178,41 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
160 */ 178 */
161 (void)acpi_tb_verify_checksum(table, length); 179 (void)acpi_tb_verify_checksum(table, length);
162 180
163 /* Copy the entire FADT locally */ 181 /*
182 * If the FADT is larger than what we know about, we have a problem.
183 * Truncate the table, but make some noise.
184 */
185 if (length > sizeof(struct acpi_table_fadt)) {
186 ACPI_WARNING((AE_INFO,
187 "FADT (revision %u) is too large, truncating length 0x%X to 0x%X",
188 table->revision, length,
189 sizeof(struct acpi_table_fadt)));
190 }
164 191
165 ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); 192 /* Copy the entire FADT locally. Zero first for tb_convert_fadt */
166 193
194 ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
167 ACPI_MEMCPY(&acpi_gbl_FADT, table, 195 ACPI_MEMCPY(&acpi_gbl_FADT, table,
168 ACPI_MIN(length, sizeof(struct acpi_table_fadt))); 196 ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
169 acpi_os_unmap_memory(table, length);
170 197
171 /* Convert local FADT to the common internal format */ 198 /* All done with the real FADT, unmap it */
199
200 acpi_os_unmap_memory(table, length);
172 201
202 /*
203 * 1) Convert the local copy of the FADT to the common internal format
204 * 2) Validate some of the important values within the FADT
205 */
173 acpi_tb_convert_fadt(); 206 acpi_tb_convert_fadt();
207 acpi_tb_validate_fadt(&acpi_gbl_FADT);
174 208
175 /* Extract the DSDT and FACS tables from the FADT */ 209 /* Obtain the DSDT and FACS tables via their addresses within the FADT */
176 210
177 acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, 211 acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
178 flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); 212 flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
179 213
180 acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, 214 acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
181 flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); 215 flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
182
183 /* Validate important FADT values */
184
185 acpi_tb_validate_fadt();
186} 216}
187 217
188/******************************************************************************* 218/*******************************************************************************
@@ -194,6 +224,7 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
194 * RETURN: None 224 * RETURN: None
195 * 225 *
196 * DESCRIPTION: Converts all versions of the FADT to a common internal format. 226 * DESCRIPTION: Converts all versions of the FADT to a common internal format.
227 * -> Expand all 32-bit addresses to 64-bit.
197 * 228 *
198 * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), 229 * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
199 * and must contain a copy of the actual FADT. 230 * and must contain a copy of the actual FADT.
@@ -213,13 +244,17 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
213 * 244 *
214 ******************************************************************************/ 245 ******************************************************************************/
215 246
216static void acpi_tb_convert_fadt(void) 247void acpi_tb_convert_fadt(void)
217{ 248{
218 u8 pm1_register_length; 249 u8 pm1_register_length;
219 struct acpi_generic_address *target; 250 struct acpi_generic_address *target;
220 acpi_native_uint i; 251 acpi_native_uint i;
221 252
222 /* Expand the FACS and DSDT addresses as necessary */ 253 /* Update the local FADT table header length */
254
255 acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
256
257 /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */
223 258
224 if (!acpi_gbl_FADT.Xfacs) { 259 if (!acpi_gbl_FADT.Xfacs) {
225 acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; 260 acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
@@ -233,10 +268,10 @@ static void acpi_tb_convert_fadt(void)
233 * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address 268 * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
234 * structures as necessary. 269 * structures as necessary.
235 */ 270 */
236 for (i = 0; i < ACPI_FADT_CONVERSION_ENTRIES; i++) { 271 for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
237 target = 272 target =
238 ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, 273 ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
239 fadt_conversion_table[i].target); 274 fadt_info_table[i].target);
240 275
241 /* Expand only if the X target is null */ 276 /* Expand only if the X target is null */
242 277
@@ -244,11 +279,11 @@ static void acpi_tb_convert_fadt(void)
244 acpi_tb_init_generic_address(target, 279 acpi_tb_init_generic_address(target,
245 *ACPI_ADD_PTR(u8, 280 *ACPI_ADD_PTR(u8,
246 &acpi_gbl_FADT, 281 &acpi_gbl_FADT,
247 fadt_conversion_table 282 fadt_info_table
248 [i].length), 283 [i].length),
249 (u64) * ACPI_ADD_PTR(u32, 284 (u64) * ACPI_ADD_PTR(u32,
250 &acpi_gbl_FADT, 285 &acpi_gbl_FADT,
251 fadt_conversion_table 286 fadt_info_table
252 [i]. 287 [i].
253 source)); 288 source));
254 } 289 }
@@ -265,14 +300,14 @@ static void acpi_tb_convert_fadt(void)
265 */ 300 */
266 pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); 301 pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
267 302
268 /* PM1A is required */ 303 /* The PM1A register block is required */
269 304
270 acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, 305 acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
271 pm1_register_length, 306 pm1_register_length,
272 (acpi_gbl_FADT.xpm1a_event_block.address + 307 (acpi_gbl_FADT.xpm1a_event_block.address +
273 pm1_register_length)); 308 pm1_register_length));
274 309
275 /* PM1B is optional; leave null if not present */ 310 /* The PM1B register block is optional, ignore if not present */
276 311
277 if (acpi_gbl_FADT.xpm1b_event_block.address) { 312 if (acpi_gbl_FADT.xpm1b_event_block.address) {
278 acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, 313 acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
@@ -280,102 +315,84 @@ static void acpi_tb_convert_fadt(void)
280 (acpi_gbl_FADT.xpm1b_event_block. 315 (acpi_gbl_FADT.xpm1b_event_block.
281 address + pm1_register_length)); 316 address + pm1_register_length));
282 } 317 }
283
284 /* Global FADT is the new common V2.0 FADT */
285
286 acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
287} 318}
288 319
289/****************************************************************************** 320/******************************************************************************
290 * 321 *
291 * FUNCTION: acpi_tb_validate_fadt 322 * FUNCTION: acpi_tb_validate_fadt
292 * 323 *
293 * PARAMETERS: None 324 * PARAMETERS: Table - Pointer to the FADT to be validated
294 * 325 *
295 * RETURN: None 326 * RETURN: None
296 * 327 *
297 * DESCRIPTION: Validate various ACPI registers in the FADT. For problems, 328 * DESCRIPTION: Validate various important fields within the FADT. If a problem
298 * issue a message, but no status is returned. 329 * is found, issue a message, but no status is returned.
330 * Used by both the table manager and the disassembler.
331 *
332 * Possible additional checks:
333 * (acpi_gbl_FADT.pm1_event_length >= 4)
334 * (acpi_gbl_FADT.pm1_control_length >= 2)
335 * (acpi_gbl_FADT.pm_timer_length >= 4)
336 * Gpe block lengths must be multiple of 2
299 * 337 *
300 ******************************************************************************/ 338 ******************************************************************************/
301 339
302static void acpi_tb_validate_fadt(void) 340void acpi_tb_validate_fadt(struct acpi_table_fadt *table)
303{ 341{
342 u32 *address32;
343 struct acpi_generic_address *address64;
344 u8 length;
345 acpi_native_uint i;
304 346
305 /* These length fields have a minimum value */ 347 /* Examine all of the 64-bit extended address fields (X fields) */
306 348
307 if (acpi_gbl_FADT.pm1_event_length < 4) { 349 for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
308 acpi_tb_fadt_register_error("Pm1EventLength", 350
309 (u32) acpi_gbl_FADT. 351 /* Generate pointers to the 32-bit and 64-bit addresses and get the length */
310 pm1_event_length); 352
311 } 353 address64 =
312 354 ACPI_ADD_PTR(struct acpi_generic_address, table,
313 if (acpi_gbl_FADT.pm_timer_length < 4) { 355 fadt_info_table[i].target);
314 acpi_tb_fadt_register_error("PmTimerLength", 356 address32 = ACPI_ADD_PTR(u32, table, fadt_info_table[i].source);
315 (u32) acpi_gbl_FADT. 357 length = *ACPI_ADD_PTR(u8, table, fadt_info_table[i].length);
316 pm_timer_length); 358
317 } 359 if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
318 360 /*
319 /* These length and address fields must be non-zero */ 361 * Field is required (Pm1a_event, Pm1a_control, pm_timer).
320 362 * Both the address and length must be non-zero.
321 if (!acpi_gbl_FADT.pm1_control_length) { 363 */
322 acpi_tb_fadt_register_error("Pm1ControlLength", 0); 364 if (!address64->address || !length) {
323 } 365 ACPI_ERROR((AE_INFO,
324 366 "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X",
325 if (!acpi_gbl_FADT.xpm1a_event_block.address) { 367 fadt_info_table[i].name,
326 acpi_tb_fadt_register_error("XPm1aEventBlock.Address", 0); 368 ACPI_FORMAT_UINT64(address64->
327 } 369 address),
328 370 length));
329 if (!acpi_gbl_FADT.xpm1a_control_block.address) { 371 }
330 acpi_tb_fadt_register_error("XPm1aControlBlock.Address", 0); 372 } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
331 } 373 /*
332 374 * Field is optional (PM2Control, GPE0, GPE1) AND has its own
333 if (!acpi_gbl_FADT.xpm_timer_block.address) { 375 * length field. If present, both the address and length must be valid.
334 acpi_tb_fadt_register_error("XPmTimerBlock.Address", 0); 376 */
335 } 377 if ((address64->address && !length)
336 378 || (!address64->address && length)) {
337 /* If PM2 block is present, must have non-zero length */ 379 ACPI_WARNING((AE_INFO,
338 380 "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X",
339 if ((acpi_gbl_FADT.xpm2_control_block.address && 381 fadt_info_table[i].name,
340 !acpi_gbl_FADT.pm2_control_length)) { 382 ACPI_FORMAT_UINT64(address64->
341 acpi_tb_fadt_register_error("Pm2ControlLength", 383 address),
342 (u32) acpi_gbl_FADT. 384 length));
343 pm2_control_length); 385 }
344 } 386 }
345
346 /* Length of any valid GPE blocks must be a multiple of 2 */
347 387
348 if (acpi_gbl_FADT.xgpe0_block.address && 388 /* If both 32- and 64-bit addresses are valid (non-zero), they must match */
349 (acpi_gbl_FADT.gpe0_block_length & 1)) {
350 acpi_tb_fadt_register_error("Gpe0BlockLength",
351 (u32) acpi_gbl_FADT.
352 gpe0_block_length);
353 }
354 389
355 if (acpi_gbl_FADT.xgpe1_block.address && 390 if (address64->address && *address32 &&
356 (acpi_gbl_FADT.gpe1_block_length & 1)) { 391 (address64->address != (u64) * address32)) {
357 acpi_tb_fadt_register_error("Gpe1BlockLength", 392 ACPI_ERROR((AE_INFO,
358 (u32) acpi_gbl_FADT. 393 "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X",
359 gpe1_block_length); 394 fadt_info_table[i].name, *address32,
395 ACPI_FORMAT_UINT64(address64->address)));
396 }
360 } 397 }
361} 398}
362
363/*******************************************************************************
364 *
365 * FUNCTION: acpi_tb_fadt_register_error
366 *
367 * PARAMETERS: register_name - Pointer to string identifying register
368 * Value - Actual register contents value
369 *
370 * RETURN: None
371 *
372 * DESCRIPTION: Display FADT warning message
373 *
374 ******************************************************************************/
375
376static void acpi_tb_fadt_register_error(char *register_name, u32 value)
377{
378
379 ACPI_WARNING((AE_INFO, "Invalid FADT value in field \"%s\" = %X",
380 register_name, value));
381}