acpi_status acpi_os_get_table_by_address(acpi_physical_address address, struct acpi_table_header ** table) { u32 table_length; struct acpi_table_header *mapped_table; struct acpi_table_header *local_table = NULL; acpi_status status = AE_OK; /* Get main ACPI tables from memory on first invocation of this function */ status = osl_table_initialize(); if (ACPI_FAILURE(status)) { return (status); } /* Map the table and validate it */ status = osl_map_table(address, NULL, &mapped_table); if (ACPI_FAILURE(status)) { return (status); } /* Copy table to local buffer and return it */ table_length = ap_get_table_length(mapped_table); if (table_length == 0) { status = AE_BAD_HEADER; goto exit; } local_table = calloc(1, table_length); if (!local_table) { status = AE_NO_MEMORY; goto exit; } memcpy(local_table, mapped_table, table_length); exit: osl_unmap_table(mapped_table); *table = local_table; return (status); }
int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) { char filename[ACPI_NAME_SIZE + 16]; char instance_str[16]; ACPI_FILE file; size_t actual; u32 table_length; /* Obtain table length */ table_length = ap_get_table_length(table); /* Construct lower-case filename from the table local signature */ if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { ACPI_MOVE_NAME(filename, ACPI_RSDP_NAME); } else { ACPI_MOVE_NAME(filename, table->signature); } filename[0] = (char)ACPI_TOLOWER(filename[0]); filename[1] = (char)ACPI_TOLOWER(filename[1]); filename[2] = (char)ACPI_TOLOWER(filename[2]); filename[3] = (char)ACPI_TOLOWER(filename[3]); filename[ACPI_NAME_SIZE] = 0; /* Handle multiple SSDts - create different filenames for each */ if (instance > 0) { acpi_ut_snprintf(instance_str, sizeof(instance_str), "%u", instance); ACPI_STRCAT(filename, instance_str); } ACPI_STRCAT(filename, ACPI_TABLE_FILE_SUFFIX); if (gbl_verbose_mode) { acpi_log_error ("Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n", table->signature, filename, table->length, table->length); } /* Open the file and dump the entire table in binary mode */ file = acpi_os_open_file(filename, ACPI_FILE_WRITING | ACPI_FILE_BINARY); if (!file) { acpi_log_error("Could not open output file: %s\n", filename); return (-1); } actual = acpi_os_write_file(file, table, 1, table_length); if (actual != table_length) { acpi_log_error("Error writing binary output file: %s\n", filename); acpi_os_close_file(file); return (-1); } acpi_os_close_file(file); return (0); }
static acpi_status osl_get_bios_table(char *signature, u32 instance, struct acpi_table_header **table, acpi_physical_address * address) { struct acpi_table_header *local_table = NULL; struct acpi_table_header *mapped_table = NULL; u8 *table_data; u8 number_of_tables; u8 item_size; u32 current_instance = 0; acpi_physical_address table_address = 0; u32 table_length = 0; acpi_status status = AE_OK; u32 i; /* Handle special tables whose addresses are not in RSDT/XSDT */ if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) || ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) || ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) || ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) || ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { if (instance > 0) { return (AE_LIMIT); } /* * Get the appropriate address, either 32-bit or 64-bit. Be very * careful about the FADT length and validate table addresses. * Note: The 64-bit addresses have priority. */ if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) { if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt) { table_address = (acpi_physical_address) gbl_fadt->Xdsdt; } else if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) && gbl_fadt->dsdt) { table_address = (acpi_physical_address) gbl_fadt->dsdt; } } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs) { table_address = (acpi_physical_address) gbl_fadt->Xfacs; } else if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) && gbl_fadt->facs) { table_address = (acpi_physical_address) gbl_fadt->facs; } } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { if (!gbl_revision) { return (AE_BAD_SIGNATURE); } table_address = (acpi_physical_address) gbl_rsdp. xsdt_physical_address; } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { table_address = (acpi_physical_address) gbl_rsdp. rsdt_physical_address; } else { table_address = (acpi_physical_address) gbl_rsdp_address; signature = ACPI_SIG_RSDP; } /* Now we can get the requested special table */ status = osl_map_table(table_address, signature, &mapped_table); if (ACPI_FAILURE(status)) { return (status); } table_length = ap_get_table_length(mapped_table); } else { /* Case for a normal ACPI table */ if (osl_can_use_xsdt()) { item_size = sizeof(u64); table_data = ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header); number_of_tables = (u8)((gbl_xsdt->header.length - sizeof(struct acpi_table_header)) / item_size); } else { /* Use RSDT if XSDT is not available */ item_size = sizeof(u32); table_data = ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header); number_of_tables = (u8)((gbl_rsdt->header.length - sizeof(struct acpi_table_header)) / item_size); } /* Search RSDT/XSDT for the requested table */ for (i = 0; i < number_of_tables; ++i, table_data += item_size) { if (osl_can_use_xsdt()) { table_address = (acpi_physical_address) (*ACPI_CAST64 (table_data)); } else { table_address = (acpi_physical_address) (*ACPI_CAST32 (table_data)); } /* Skip NULL entries in RSDT/XSDT */ if (!table_address) { continue; } status = osl_map_table(table_address, NULL, &mapped_table); if (ACPI_FAILURE(status)) { return (status); } table_length = mapped_table->length; /* Does this table match the requested signature? */ if (!ACPI_COMPARE_NAME (mapped_table->signature, signature)) { osl_unmap_table(mapped_table); mapped_table = NULL; continue; } /* Match table instance (for SSDT/UEFI tables) */ if (current_instance != instance) { osl_unmap_table(mapped_table); mapped_table = NULL; current_instance++; continue; } break; } } if (!mapped_table) { return (AE_LIMIT); } if (table_length == 0) { status = AE_BAD_HEADER; goto exit; } /* Copy table to local buffer and return it */ local_table = calloc(1, table_length); if (!local_table) { status = AE_NO_MEMORY; goto exit; } ACPI_MEMCPY(local_table, mapped_table, table_length); *address = table_address; *table = local_table; exit: osl_unmap_table(mapped_table); return (status); }
static acpi_status osl_read_table_from_file(char *filename, acpi_size file_offset, char *signature, struct acpi_table_header **table) { FILE *table_file; struct acpi_table_header header; struct acpi_table_header *local_table = NULL; u32 table_length; s32 count; acpi_status status = AE_OK; /* Open the file */ table_file = fopen(filename, "rb"); if (table_file == NULL) { fprintf(stderr, "Could not open table file: %s\n", filename); return (osl_get_last_status(AE_NOT_FOUND)); } fseek(table_file, file_offset, SEEK_SET); /* Read the Table header to get the table length */ count = fread(&header, 1, sizeof(struct acpi_table_header), table_file); if (count != sizeof(struct acpi_table_header)) { fprintf(stderr, "Could not read table header: %s\n", filename); status = AE_BAD_HEADER; goto exit; } /* If signature is specified, it must match the table */ if (signature) { if (ACPI_VALIDATE_RSDP_SIG(signature)) { if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) { fprintf(stderr, "Incorrect RSDP signature: found %8.8s\n", header.signature); status = AE_BAD_SIGNATURE; goto exit; } } else if (!ACPI_COMPARE_NAME(signature, header.signature)) { fprintf(stderr, "Incorrect signature: Expecting %4.4s, found %4.4s\n", signature, header.signature); status = AE_BAD_SIGNATURE; goto exit; } } table_length = ap_get_table_length(&header); if (table_length == 0) { status = AE_BAD_HEADER; goto exit; } /* Read the entire table into a local buffer */ local_table = calloc(1, table_length); if (!local_table) { fprintf(stderr, "%4.4s: Could not allocate buffer for table of length %X\n", header.signature, table_length); status = AE_NO_MEMORY; goto exit; } fseek(table_file, file_offset, SEEK_SET); count = fread(local_table, 1, table_length, table_file); if (count != table_length) { fprintf(stderr, "%4.4s: Could not read table content\n", header.signature); status = AE_INVALID_TABLE_LENGTH; goto exit; } /* Validate checksum */ (void)ap_is_valid_checksum(local_table); exit: fclose(table_file); *table = local_table; return (status); }
static void osl_unmap_table(struct acpi_table_header *table) { if (table) { acpi_os_unmap_memory(table, ap_get_table_length(table)); } }
static acpi_status osl_map_table(acpi_size address, char *signature, struct acpi_table_header **table) { struct acpi_table_header *mapped_table; u32 length; if (!address) { return (AE_BAD_ADDRESS); } /* * Map the header so we can get the table length. * Use sizeof (struct acpi_table_header) as: * 1. it is bigger than 24 to include RSDP->Length * 2. it is smaller than sizeof (struct acpi_table_rsdp) */ mapped_table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); if (!mapped_table) { fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n", ACPI_FORMAT_UINT64(address)); return (osl_get_last_status(AE_BAD_ADDRESS)); } /* If specified, signature must match */ if (signature) { if (ACPI_VALIDATE_RSDP_SIG(signature)) { if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) { acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header)); return (AE_BAD_SIGNATURE); } } else if (!ACPI_COMPARE_NAME(signature, mapped_table->signature)) { acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header)); return (AE_BAD_SIGNATURE); } } /* Map the entire table */ length = ap_get_table_length(mapped_table); acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header)); if (length == 0) { return (AE_BAD_HEADER); } mapped_table = acpi_os_map_memory(address, length); if (!mapped_table) { fprintf(stderr, "Could not map table at 0x%8.8X%8.8X length %8.8X\n", ACPI_FORMAT_UINT64(address), length); return (osl_get_last_status(AE_INVALID_TABLE_LENGTH)); } (void)ap_is_valid_checksum(mapped_table); *table = mapped_table; return (AE_OK); }