acpi_status acpi_tb_get_table_rsdt ( void) { struct acpi_table_desc table_info; acpi_status status; struct acpi_pointer address; ACPI_FUNCTION_TRACE ("tb_get_table_rsdt"); /* Get the RSDT/XSDT via the RSDP */ acpi_tb_get_rsdt_address (&address); table_info.type = ACPI_TABLE_XSDT; status = acpi_tb_get_table (&address, &table_info); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT/XSDT, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP located at %p, points to RSDT physical=%8.8X%8.8X \n", acpi_gbl_RSDP, ACPI_FORMAT_UINT64 (address.pointer.value))); /* Check the RSDT or XSDT signature */ status = acpi_tb_validate_rsdt (table_info.pointer); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Get the number of tables defined in the RSDT or XSDT */ acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info.pointer); /* Convert and/or copy to an XSDT structure */ status = acpi_tb_convert_to_xsdt (&table_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Save the table pointers and allocation info */ status = acpi_tb_init_table_descriptor (ACPI_TABLE_XSDT, &table_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } acpi_gbl_XSDT = ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info.pointer); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT)); return_ACPI_STATUS (status); }
/******************************************************************************* * * FUNCTION: acpi_get_table * * PARAMETERS: signature - ACPI signature of needed table * instance - Which instance (for SSDTs) * out_table - Where the pointer to the table is returned * * RETURN: Status and pointer to the requested table * * DESCRIPTION: Finds and verifies an ACPI table. Table must be in the * RSDT/XSDT. * Note that an early stage acpi_get_table() call must be paired * with an early stage acpi_put_table() call. otherwise the table * pointer mapped by the early stage mapping implementation may be * erroneously unmapped by the late stage unmapping implementation * in an acpi_put_table() invoked during the late stage. * ******************************************************************************/ acpi_status acpi_get_table(char *signature, u32 instance, struct acpi_table_header ** out_table) { u32 i; u32 j; acpi_status status = AE_NOT_FOUND; struct acpi_table_desc *table_desc; /* Parameter validation */ if (!signature || !out_table) { return (AE_BAD_PARAMETER); } /* * Note that the following line is required by some OSPMs, they only * check if the returned table is NULL instead of the returned status * to determined if this function is succeeded. */ *out_table = NULL; (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); /* Walk the root table list */ for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { table_desc = &acpi_gbl_root_table_list.tables[i]; if (!ACPI_COMPARE_NAME(&table_desc->signature, signature)) { continue; } if (++j < instance) { continue; } status = acpi_tb_get_table(table_desc, out_table); break; } (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return (status); }
acpi_status acpi_load_table ( acpi_table_header *table_ptr) { acpi_status status; acpi_table_desc table_info; FUNCTION_TRACE ("Acpi_load_table"); if (!table_ptr) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Copy the table to a local buffer */ status = acpi_tb_get_table (0, table_ptr, &table_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Install the new table into the local data structures */ status = acpi_tb_install_table (NULL, &table_info); if (ACPI_FAILURE (status)) { /* Free table allocated by Acpi_tb_get_table */ acpi_tb_delete_single_table (&table_info); return_ACPI_STATUS (status); } status = acpi_ns_load_table (table_info.installed_desc, acpi_gbl_root_node); if (ACPI_FAILURE (status)) { /* Uninstall table and free the buffer */ acpi_tb_uninstall_table (table_info.installed_desc); return_ACPI_STATUS (status); } return_ACPI_STATUS (status); }
/******************************************************************************* * * FUNCTION: acpi_get_table_by_index * * PARAMETERS: table_index - Table index * out_table - Where the pointer to the table is returned * * RETURN: Status and pointer to the requested table * * DESCRIPTION: Obtain a table by an index into the global table list. Used * internally also. * ******************************************************************************/ acpi_status acpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table) { acpi_status status; ACPI_FUNCTION_TRACE(acpi_get_table_by_index); /* Parameter validation */ if (!out_table) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* * Note that the following line is required by some OSPMs, they only * check if the returned table is NULL instead of the returned status * to determined if this function is succeeded. */ *out_table = NULL; (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); /* Validate index */ if (table_index >= acpi_gbl_root_table_list.current_table_count) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } status = acpi_tb_get_table(&acpi_gbl_root_table_list.tables[table_index], out_table); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); }
acpi_status acpi_get_firmware_table ( acpi_string signature, u32 instance, u32 flags, struct acpi_table_header **table_pointer) { struct acpi_pointer rsdp_address; struct acpi_pointer address; acpi_status status; struct acpi_table_header header; struct acpi_table_desc table_info; struct acpi_table_desc rsdt_info; u32 table_count; u32 i; u32 j; ACPI_FUNCTION_TRACE ("acpi_get_firmware_table"); /* * Ensure that at least the table manager is initialized. We don't * require that the entire ACPI subsystem is up for this interface */ /* * If we have a buffer, we must have a length too */ if ((instance == 0) || (!signature) || (!table_pointer)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } rsdt_info.pointer = NULL; if (!acpi_gbl_RSDP) { /* Get the RSDP */ status = acpi_os_get_root_pointer (flags, &rsdp_address); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } /* Map and validate the RSDP */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { status = acpi_os_map_memory (rsdp_address.pointer.physical, sizeof (struct rsdp_descriptor), (void *) &acpi_gbl_RSDP); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } else { acpi_gbl_RSDP = rsdp_address.pointer.logical; } /* * The signature and checksum must both be correct */ if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { /* Nope, BAD Signature */ return_ACPI_STATUS (AE_BAD_SIGNATURE); } if (acpi_tb_checksum (acpi_gbl_RSDP, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { /* Nope, BAD Checksum */ return_ACPI_STATUS (AE_BAD_CHECKSUM); } } /* Get the RSDT and validate it */ acpi_tb_get_rsdt_address (&address); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", acpi_gbl_RSDP, ACPI_HIDWORD (address.pointer.value), ACPI_LODWORD (address.pointer.value))); /* Insert processor_mode flags */ address.pointer_type |= flags; status = acpi_tb_get_table (&address, &rsdt_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } status = acpi_tb_validate_rsdt (rsdt_info.pointer); if (ACPI_FAILURE (status)) { goto cleanup; } /* Get the number of table pointers within the RSDT */ table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_info.pointer); address.pointer_type = acpi_gbl_table_flags | flags; /* * Search the RSDT/XSDT for the correct instance of the * requested table */ for (i = 0, j = 0; i < table_count; i++) { /* Get the next table pointer, handle RSDT vs. XSDT */ if (acpi_gbl_RSDP->revision < 2) { address.pointer.value = ((RSDT_DESCRIPTOR *) rsdt_info.pointer)->table_offset_entry[i]; } else { address.pointer.value = ((XSDT_DESCRIPTOR *) rsdt_info.pointer)->table_offset_entry[i]; } /* Get the table header */ status = acpi_tb_get_table_header (&address, &header); if (ACPI_FAILURE (status)) { goto cleanup; } /* Compare table signatures and table instance */ if (!ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) { /* An instance of the table was found */ j++; if (j >= instance) { /* Found the correct instance, get the entire table */ status = acpi_tb_get_table_body (&address, &header, &table_info); if (ACPI_FAILURE (status)) { goto cleanup; } *table_pointer = table_info.pointer; goto cleanup; } } } /* Did not find the table */ status = AE_NOT_EXIST; cleanup: acpi_os_unmap_memory (rsdt_info.pointer, (acpi_size) rsdt_info.pointer->length); return_ACPI_STATUS (status); }
acpi_status acpi_get_firmware_table(acpi_string signature, u32 instance, u32 flags, struct acpi_table_header **table_pointer) { acpi_status status; struct acpi_pointer address; struct acpi_table_header *header = NULL; struct acpi_table_desc *table_info = NULL; struct acpi_table_desc *rsdt_info; u32 table_count; u32 i; u32 j; ACPI_FUNCTION_TRACE("acpi_get_firmware_table"); /* * Ensure that at least the table manager is initialized. We don't * require that the entire ACPI subsystem is up for this interface. * If we have a buffer, we must have a length too */ if ((instance == 0) || (!signature) || (!table_pointer)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Ensure that we have a RSDP */ if (!acpi_gbl_RSDP) { /* Get the RSDP */ status = acpi_os_get_root_pointer(flags, &address); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n")); return_ACPI_STATUS(AE_NO_ACPI_TABLES); } /* Map and validate the RSDP */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { status = acpi_os_map_memory(address.pointer.physical, sizeof(struct rsdp_descriptor), (void *)&acpi_gbl_RSDP); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } else { acpi_gbl_RSDP = address.pointer.logical; } /* The RDSP signature and checksum must both be correct */ status = acpi_tb_validate_rsdp(acpi_gbl_RSDP); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } /* Get the RSDT address via the RSDP */ acpi_tb_get_rsdt_address(&address); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", acpi_gbl_RSDP, ACPI_FORMAT_UINT64(address.pointer.value))); /* Insert processor_mode flags */ address.pointer_type |= flags; /* Get and validate the RSDT */ rsdt_info = ACPI_MEM_CALLOCATE(sizeof(struct acpi_table_desc)); if (!rsdt_info) { return_ACPI_STATUS(AE_NO_MEMORY); } status = acpi_tb_get_table(&address, rsdt_info); if (ACPI_FAILURE(status)) { goto cleanup; } status = acpi_tb_validate_rsdt(rsdt_info->pointer); if (ACPI_FAILURE(status)) { goto cleanup; } /* Allocate a scratch table header and table descriptor */ header = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_header)); if (!header) { status = AE_NO_MEMORY; goto cleanup; } table_info = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_desc)); if (!table_info) { status = AE_NO_MEMORY; goto cleanup; } /* Get the number of table pointers within the RSDT */ table_count = acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer); address.pointer_type = acpi_gbl_table_flags | flags; /* * Search the RSDT/XSDT for the correct instance of the * requested table */ for (i = 0, j = 0; i < table_count; i++) { /* * Get the next table pointer, handle RSDT vs. XSDT * RSDT pointers are 32 bits, XSDT pointers are 64 bits */ if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { address.pointer.value = (ACPI_CAST_PTR (RSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i]; } else { address.pointer.value = (ACPI_CAST_PTR (XSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i]; } /* Get the table header */ status = acpi_tb_get_table_header(&address, header); if (ACPI_FAILURE(status)) { goto cleanup; } /* Compare table signatures and table instance */ if (!ACPI_STRNCMP(header->signature, signature, ACPI_NAME_SIZE)) { /* An instance of the table was found */ j++; if (j >= instance) { /* Found the correct instance, get the entire table */ status = acpi_tb_get_table_body(&address, header, table_info); if (ACPI_FAILURE(status)) { goto cleanup; } *table_pointer = table_info->pointer; goto cleanup; } } } /* Did not find the table */ status = AE_NOT_EXIST; cleanup: if (rsdt_info->pointer) { acpi_os_unmap_memory(rsdt_info->pointer, (acpi_size) rsdt_info->pointer->length); } ACPI_MEM_FREE(rsdt_info); if (header) { ACPI_MEM_FREE(header); } if (table_info) { ACPI_MEM_FREE(table_info); } return_ACPI_STATUS(status); }
void acpi_tb_parse_fadt(void) { u32 length; struct acpi_table_header *table; struct acpi_table_desc *fadt_desc; acpi_status status; /* * The FADT has multiple versions with different lengths, * and it contains pointers to both the DSDT and FACS tables. * * Get a local copy of the FADT and convert it to a common format * Map entire FADT, assumed to be smaller than one page. */ fadt_desc = &acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index]; status = acpi_tb_get_table(fadt_desc, &table); if (ACPI_FAILURE(status)) { return; } length = fadt_desc->length; /* * Validate the FADT checksum before we copy the table. Ignore * checksum error as we want to try to get the DSDT and FACS. */ (void)acpi_tb_verify_checksum(table, length); /* Create a local copy of the FADT in common ACPI 2.0+ format */ acpi_tb_create_local_fadt(table, length); /* All done with the real FADT, unmap it */ acpi_tb_put_table(fadt_desc); /* Obtain the DSDT and FACS tables via their addresses within the FADT */ acpi_tb_install_standard_table((acpi_physical_address)acpi_gbl_FADT. Xdsdt, ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, FALSE, TRUE, &acpi_gbl_dsdt_index); /* If Hardware Reduced flag is set, there is no FACS */ if (!acpi_gbl_reduced_hardware) { if (acpi_gbl_FADT.facs) { acpi_tb_install_standard_table((acpi_physical_address) acpi_gbl_FADT.facs, ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, FALSE, TRUE, &acpi_gbl_facs_index); } if (acpi_gbl_FADT.Xfacs) { acpi_tb_install_standard_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, FALSE, TRUE, &acpi_gbl_xfacs_index); } } }