ACPI_STATUS acpi_tb_map_acpi_table ( ACPI_PHYSICAL_ADDRESS physical_address, u32 *size, void **logical_address) { ACPI_TABLE_HEADER *table; u32 table_size = *size; ACPI_STATUS status = AE_OK; /* If size is zero, look at the table header to get the actual size */ if ((*size) == 0) { /* Get the table header so we can extract the table length */ status = acpi_os_map_memory (physical_address, sizeof (ACPI_TABLE_HEADER), (void **) &table); if (ACPI_FAILURE (status)) { return (status); } /* Extract the full table length before we delete the mapping */ table_size = table->length; /* * Validate the header and delete the mapping. * We will create a mapping for the full table below. */ status = acpi_tb_validate_table_header (table); /* Always unmap the memory for the header */ acpi_os_unmap_memory (table, sizeof (ACPI_TABLE_HEADER)); /* Exit if header invalid */ if (ACPI_FAILURE (status)) { return (status); } } /* Map the physical memory for the correct length */ status = acpi_os_map_memory (physical_address, table_size, (void **) &table); if (ACPI_FAILURE (status)) { return (status); } *size = table_size; *logical_address = table; return (status); }
/****************************************************************************** * * FUNCTION: acpi_tb_verify_table * * PARAMETERS: table_desc - table * * RETURN: Status * * DESCRIPTION: this function is called to verify and map table * *****************************************************************************/ acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) { acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(tb_verify_table); /* Map the table if necessary */ if (!table_desc->pointer) { if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == ACPI_TABLE_ORIGIN_MAPPED) { table_desc->pointer = acpi_os_map_memory(table_desc->address, table_desc->length); } if (!table_desc->pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } } /* FACS is the odd table, has no standard ACPI header and no checksum */ if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) { /* Always calculate checksum, ignore bad checksum if requested */ status = acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); } return_ACPI_STATUS(status); }
/****************************************************************************** * * FUNCTION: acpi_tb_verify_table * * PARAMETERS: table_desc - table * * RETURN: Status * * DESCRIPTION: this function is called to verify and map table * *****************************************************************************/ acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) { acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(tb_verify_table); /* Map the table if necessary */ if (!table_desc->pointer) { if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == ACPI_TABLE_ORIGIN_MAPPED) { table_desc->pointer = acpi_os_map_memory(table_desc->address, table_desc->length); } if (!table_desc->pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } } /* Always calculate checksum, ignore bad checksum if requested */ status = acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); return_ACPI_STATUS(status); }
acpi_status acpi_tb_get_table_header ( struct acpi_pointer *address, struct acpi_table_header *return_header) { acpi_status status = AE_OK; struct acpi_table_header *header = NULL; ACPI_FUNCTION_TRACE ("tb_get_table_header"); /* * Flags contains the current processor mode (Virtual or Physical * addressing) The pointer_type is either Logical or Physical */ switch (address->pointer_type) { case ACPI_PHYSMODE_PHYSPTR: case ACPI_LOGMODE_LOGPTR: /* Pointer matches processor mode, copy the header */ ACPI_MEMCPY (return_header, address->pointer.logical, sizeof (struct acpi_table_header)); break; case ACPI_LOGMODE_PHYSPTR: /* Create a logical address for the physical pointer*/ status = acpi_os_map_memory (address->pointer.physical, sizeof (struct acpi_table_header), (void *) &header); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "Could not map memory at %8.8X%8.8X for length %X\n", ACPI_FORMAT_UINT64 (address->pointer.physical), sizeof (struct acpi_table_header))); return_ACPI_STATUS (status); } /* Copy header and delete mapping */ ACPI_MEMCPY (return_header, header, sizeof (struct acpi_table_header)); acpi_os_unmap_memory (header, sizeof (struct acpi_table_header)); break; default: ACPI_REPORT_ERROR (("Invalid address flags %X\n", address->pointer_type)); return_ACPI_STATUS (AE_BAD_PARAMETER); } ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n", return_header->signature)); return_ACPI_STATUS (AE_OK); }
void acpi_tb_parse_fadt(u32 table_index) { u32 length; struct acpi_table_header *table; length = acpi_gbl_root_table_list.tables[table_index].length; table = acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index]. address, length); if (!table) { return; } (void)acpi_tb_verify_checksum(table, length); acpi_tb_create_local_fadt(table, length); acpi_os_unmap_memory(table, length); acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); }
acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) { acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(tb_verify_table); if (!table_desc->pointer) { if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == ACPI_TABLE_ORIGIN_MAPPED) { table_desc->pointer = acpi_os_map_memory(table_desc->address, table_desc->length); } if (!table_desc->pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } } if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) { status = acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); } return_ACPI_STATUS(status); }
/****************************************************************************** * * FUNCTION: acpi_get_table_header * * PARAMETERS: Signature - ACPI signature of needed table * Instance - Which instance (for SSDTs) * out_table_header - The pointer to the table header to fill * * RETURN: Status and pointer to mapped table header * * DESCRIPTION: Finds an ACPI table header. * * NOTE: Caller is responsible in unmapping the header with * acpi_os_unmap_memory * *****************************************************************************/ acpi_status acpi_get_table_header(char *signature, acpi_native_uint instance, struct acpi_table_header * out_table_header) { acpi_native_uint i; acpi_native_uint j; struct acpi_table_header *header; /* Parameter validation */ if (!signature || !out_table_header) { return (AE_BAD_PARAMETER); } /* * Walk the root table list */ for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) { if (!ACPI_COMPARE_NAME (&(acpi_gbl_root_table_list.tables[i].signature), signature)) { continue; } if (++j < instance) { continue; } if (!acpi_gbl_root_table_list.tables[i].pointer) { if ((acpi_gbl_root_table_list.tables[i]. flags & ACPI_TABLE_ORIGIN_MASK) == ACPI_TABLE_ORIGIN_MAPPED) { header = acpi_os_map_memory(acpi_gbl_root_table_list. tables[i].address, sizeof(struct acpi_table_header)); if (!header) { return AE_NO_MEMORY; } ACPI_MEMCPY(out_table_header, header, sizeof(struct acpi_table_header)); acpi_os_unmap_memory(header, sizeof(struct acpi_table_header)); } else { return AE_NOT_FOUND; } } else { ACPI_MEMCPY(out_table_header, acpi_gbl_root_table_list.tables[i].pointer, sizeof(struct acpi_table_header)); } return (AE_OK); } return (AE_NOT_FOUND); }
static acpi_status acpi_tb_check_xsdt(acpi_physical_address address) { struct acpi_table_header *table; u32 length; u64 xsdt_entry_address; u8 *table_entry; u32 table_count; int i; /* map table header, verify length */ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); if (!table) return AE_NO_MEMORY; length = table->length; /* length of entire table, incl header */ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); if (length < sizeof(struct acpi_table_header)) return AE_INVALID_TABLE_LENGTH; /* map entire table, not just header */ table = acpi_os_map_memory(address, length); if (!table) return AE_NO_MEMORY; /* Calculate the number of tables described in XSDT */ table_count = (u32) ((table->length - sizeof(struct acpi_table_header)) / sizeof(u64)); table_entry = ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); for (i = 0; i < table_count; i++) { ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry); if (!xsdt_entry_address) { /* XSDT has NULL entry */ break; } table_entry += sizeof(u64); } acpi_os_unmap_memory(table, length); if (i < table_count) return AE_NULL_ENTRY; else return AE_OK; }
static acpi_status acpi_table_initrd_override(struct acpi_table_header *existing_table, acpi_physical_address *address, u32 *length) { int table_offset = 0; int table_index = 0; struct acpi_table_header *table; u32 table_length; *length = 0; *address = 0; if (!acpi_tables_addr) return AE_OK; while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) { table = acpi_os_map_memory(acpi_tables_addr + table_offset, ACPI_HEADER_SIZE); if (table_offset + table->length > all_tables_size) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); WARN_ON(1); return AE_OK; } table_length = table->length; /* Only override tables matched */ if (memcmp(existing_table->signature, table->signature, 4) || memcmp(table->oem_id, existing_table->oem_id, ACPI_OEM_ID_SIZE) || memcmp(table->oem_table_id, existing_table->oem_table_id, ACPI_OEM_TABLE_ID_SIZE)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } /* * Mark the table to avoid being used in * acpi_table_initrd_scan() and check the revision. */ if (test_and_set_bit(table_index, acpi_initrd_installed) || existing_table->oem_revision >= table->oem_revision) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } *length = table_length; *address = acpi_tables_addr + table_offset; pr_info("Table Upgrade: override [%4.4s-%6.6s-%8.8s]\n", table->signature, table->oem_id, table->oem_table_id); acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); break; next_table: table_offset += table_length; table_index++; } return AE_OK; }
void acpi_tb_parse_fadt(u32 table_index) { u32 length; struct acpi_table_header *table; /* * 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. */ length = acpi_gbl_root_table_list.tables[table_index].length; table = acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index]. address, length); if (!table) { return; } /* * 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_os_unmap_memory(table, length); /* Obtain the DSDT and FACS tables via their addresses within the FADT */ acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, ACPI_SIG_DSDT, &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_fixed_table((acpi_physical_address) acpi_gbl_FADT.facs, ACPI_SIG_FACS, &acpi_gbl_facs_index); } if (acpi_gbl_FADT.Xfacs) { acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS, &acpi_gbl_xfacs_index); } } }
static acpi_status acpi_tb_check_xsdt(acpi_physical_address address) { struct acpi_table_header *table; u32 length; u64 xsdt_entry_address; u8 *table_entry; u32 table_count; int i; table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); if (!table) return AE_NO_MEMORY; length = table->length; acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); if (length < sizeof(struct acpi_table_header)) return AE_INVALID_TABLE_LENGTH; table = acpi_os_map_memory(address, length); if (!table) return AE_NO_MEMORY; table_count = (u32) ((table->length - sizeof(struct acpi_table_header)) / sizeof(u64)); table_entry = ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); for (i = 0; i < table_count; i++) { ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry); if (!xsdt_entry_address) { break; } table_entry += sizeof(u64); } acpi_os_unmap_memory(table, length); if (i < table_count) return AE_NULL_ENTRY; else return AE_OK; }
static void __init acpi_table_initrd_scan(void) { int table_offset = 0; int table_index = 0; u32 table_length; struct acpi_table_header *table; if (!acpi_tables_addr) return; while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) { table = acpi_os_map_memory(acpi_tables_addr + table_offset, ACPI_HEADER_SIZE); if (table_offset + table->length > all_tables_size) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); WARN_ON(1); return; } table_length = table->length; /* Skip RSDT/XSDT which should only be used for override */ if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) || ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } /* * Mark the table to avoid being used in * acpi_table_initrd_override(). Though this is not possible * because override is disabled in acpi_install_table(). */ if (test_and_set_bit(table_index, acpi_initrd_installed)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s]\n", table->signature, table->oem_id, table->oem_table_id); acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); acpi_install_table(acpi_tables_addr + table_offset, TRUE); next_table: table_offset += table_length; table_index++; } }
acpi_status acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, acpi_physical_address address, u8 flags) { struct acpi_table_header *table_header; switch (flags & ACPI_TABLE_ORIGIN_MASK) { case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: /* Get the length of the full table from the header */ table_header = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); if (!table_header) { return (AE_NO_MEMORY); } acpi_tb_init_table_descriptor(table_desc, address, flags, table_header); acpi_os_unmap_memory(table_header, sizeof(struct acpi_table_header)); return (AE_OK); case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: table_header = ACPI_CAST_PTR(struct acpi_table_header, ACPI_PHYSADDR_TO_PTR(address)); if (!table_header) { return (AE_NO_MEMORY); } acpi_tb_init_table_descriptor(table_desc, address, flags, table_header); return (AE_OK); default: break; } /* Table is not valid yet */ return (AE_NO_MEMORY); }
static acpi_status osl_load_rsdp(void) { struct acpi_table_header *mapped_table; u8 *rsdp_address; acpi_physical_address rsdp_base; acpi_size rsdp_size; /* Get RSDP from memory */ rsdp_size = sizeof(struct acpi_table_rsdp); if (gbl_rsdp_base) { rsdp_base = gbl_rsdp_base; } else { rsdp_base = osl_find_rsdp_via_efi(); } if (!rsdp_base) { rsdp_base = ACPI_HI_RSDP_WINDOW_BASE; rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE; } rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size); if (!rsdp_address) { return (osl_get_last_status(AE_BAD_ADDRESS)); } /* Search low memory for the RSDP */ mapped_table = ACPI_CAST_PTR(struct acpi_table_header, acpi_tb_scan_memory_for_rsdp(rsdp_address, rsdp_size)); if (!mapped_table) { acpi_os_unmap_memory(rsdp_address, rsdp_size); return (AE_NOT_FOUND); } gbl_rsdp_address = rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address); memcpy(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp)); acpi_os_unmap_memory(rsdp_address, rsdp_size); return (AE_OK); }
void __init acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags) { u32 length; struct acpi_table_header *table; /* * 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. */ length = acpi_gbl_root_table_list.tables[table_index].length; table = acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index]. address, length); if (!table) { return; } /* * 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); /* Obtain 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_os_unmap_memory(table, length); /* Obtain the DSDT and FACS tables via their addresses within the FADT */ acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); }
int acpi_os_map_generic_address(struct acpi_generic_address *gas) { u64 addr; void __iomem *virt; if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return 0; /* Handle possible alignment issues */ memcpy(&addr, &gas->address, sizeof(addr)); if (!addr || !gas->bit_width) return -EINVAL; virt = acpi_os_map_memory(addr, gas->bit_width / 8); if (!virt) return -EIO; return 0; }
struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header *table_header, struct acpi_table_desc *table_desc) { acpi_status status; struct acpi_table_header *new_table = NULL; acpi_physical_address new_address = 0; u32 new_table_length = 0; u8 new_flags; char *override_type; /* (1) Attempt logical override (returns a logical address) */ status = acpi_os_table_override(table_header, &new_table); if (ACPI_SUCCESS(status) && new_table) { new_address = ACPI_PTR_TO_PHYSADDR(new_table); new_table_length = new_table->length; new_flags = ACPI_TABLE_ORIGIN_OVERRIDE; override_type = "Logical"; goto finish_override; } /* (2) Attempt physical override (returns a physical address) */ status = acpi_os_physical_table_override(table_header, &new_address, &new_table_length); if (ACPI_SUCCESS(status) && new_address && new_table_length) { /* Map the entire new table */ new_table = acpi_os_map_memory(new_address, new_table_length); if (!new_table) { ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "%4.4s %p Attempted physical table override failed", table_header->signature, ACPI_CAST_PTR(void, table_desc->address))); return (NULL); }
acpi_status acpi_tb_acquire_table(struct acpi_table_desc *table_desc, struct acpi_table_header **table_ptr, u32 *table_length, u8 *table_flags) { struct acpi_table_header *table = NULL; switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: table = acpi_os_map_memory(table_desc->address, table_desc->length); break; case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: table = ACPI_CAST_PTR(struct acpi_table_header, ACPI_PHYSADDR_TO_PTR(table_desc-> address)); break; default: break; } /* Table is not valid yet */ if (!table) { return (AE_NO_MEMORY); } /* Fill the return values */ *table_ptr = table; *table_length = table_desc->length; *table_flags = table_desc->flags; return (AE_OK); }
void acpi_tb_install_table(acpi_physical_address address, char *signature, u32 table_index) { struct acpi_table_header *table; struct acpi_table_header *final_table; struct acpi_table_desc *table_desc; if (!address) { ACPI_ERROR((AE_INFO, "Null physical address for ACPI table [%s]", signature)); return; } /* Map just the table header */ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); if (!table) { ACPI_ERROR((AE_INFO, "Could not map memory for table [%s] at %p", signature, ACPI_CAST_PTR(void, address))); return; }
acpi_status acpi_os_physical_table_override(struct acpi_table_header *existing_table, acpi_physical_address *address, u32 *table_length) { #ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE *table_length = 0; *address = 0; return AE_OK; #else int table_offset = 0; struct acpi_table_header *table; *table_length = 0; *address = 0; if (!acpi_tables_addr) return AE_OK; do { if (table_offset + ACPI_HEADER_SIZE > all_tables_size) { WARN_ON(1); return AE_OK; } table = acpi_os_map_memory(acpi_tables_addr + table_offset, ACPI_HEADER_SIZE); if (table_offset + table->length > all_tables_size) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); WARN_ON(1); return AE_OK; } table_offset += table->length; if (memcmp(existing_table->signature, table->signature, 4)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); continue; } /* Only override tables with matching oem id */ if (memcmp(table->oem_table_id, existing_table->oem_table_id, ACPI_OEM_TABLE_ID_SIZE)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); continue; } table_offset -= table->length; *table_length = table->length; acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); *address = acpi_tables_addr + table_offset; break; } while (table_offset + ACPI_HEADER_SIZE < all_tables_size); if (*address != 0) acpi_table_taint(existing_table); return AE_OK; #endif }
static acpi_status acpi_tb_get_this_table ( struct acpi_pointer *address, struct acpi_table_header *header, struct acpi_table_desc *table_info) { struct acpi_table_header *full_table = NULL; u8 allocation; acpi_status status = AE_OK; ACPI_FUNCTION_TRACE ("tb_get_this_table"); /* * Flags contains the current processor mode (Virtual or Physical * addressing) The pointer_type is either Logical or Physical */ switch (address->pointer_type) { case ACPI_PHYSMODE_PHYSPTR: case ACPI_LOGMODE_LOGPTR: /* Pointer matches processor mode, copy the table to a new buffer */ full_table = ACPI_MEM_ALLOCATE (header->length); if (!full_table) { ACPI_REPORT_ERROR (( "Could not allocate table memory for [%4.4s] length %X\n", header->signature, header->length)); return_ACPI_STATUS (AE_NO_MEMORY); } /* Copy the entire table (including header) to the local buffer */ ACPI_MEMCPY (full_table, address->pointer.logical, header->length); /* Save allocation type */ allocation = ACPI_MEM_ALLOCATED; break; case ACPI_LOGMODE_PHYSPTR: /* * Just map the table's physical memory * into our address space. */ status = acpi_os_map_memory (address->pointer.physical, (acpi_size) header->length, (void *) &full_table); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", header->signature, ACPI_FORMAT_UINT64 (address->pointer.physical), header->length)); return (status); } /* Save allocation type */ allocation = ACPI_MEM_MAPPED; break; default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid address flags %X\n", address->pointer_type)); return_ACPI_STATUS (AE_BAD_PARAMETER); } /* * Validate checksum for _most_ tables, * even the ones whose signature we don't recognize */ if (table_info->type != ACPI_TABLE_FACS) { status = acpi_tb_verify_table_checksum (full_table); #if (!ACPI_CHECKSUM_ABORT) if (ACPI_FAILURE (status)) { /* Ignore the error if configuration says so */ status = AE_OK; } #endif } /* Return values */ table_info->pointer = full_table; table_info->length = (acpi_size) header->length; table_info->allocation = allocation; ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n", full_table->signature, ACPI_FORMAT_UINT64 (address->pointer.physical), full_table)); return_ACPI_STATUS (status); }
acpi_status acpi_ex_system_memory_space_handler ( u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, u32 *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; void *logical_addr_ptr = NULL; acpi_mem_space_context *mem_info = region_context; u32 length; FUNCTION_TRACE ("Ex_system_memory_space_handler"); /* Validate and translate the bit width */ switch (bit_width) { case 8: length = 1; break; case 16: length = 2; break; case 32: length = 4; break; default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid System_memory width %d\n", bit_width)); return_ACPI_STATUS (AE_AML_OPERAND_VALUE); break; } /* * Does the request fit into the cached memory mapping? * Is 1) Address below the current mapping? OR * 2) Address beyond the current mapping? */ if ((address < mem_info->mapped_physical_address) || (((acpi_integer) address + length) > ((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; * Delete the existing mapping and create a new one. */ if (mem_info->mapped_length) { /* Valid mapping, delete it */ acpi_os_unmap_memory (mem_info->mapped_logical_address, mem_info->mapped_length); } mem_info->mapped_length = 0; /* In case of failure below */ /* Create a new mapping starting at the address given */ status = acpi_os_map_memory (address, SYSMEM_REGION_WINDOW_SIZE, (void **) &mem_info->mapped_logical_address); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Save the physical address and mapping size */ mem_info->mapped_physical_address = address; mem_info->mapped_length = SYSMEM_REGION_WINDOW_SIZE; } /* * Generate a logical pointer corresponding to the address we want to * access */ /* TBD: should these pointers go to 64-bit in all cases ? */ logical_addr_ptr = mem_info->mapped_logical_address + ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "System_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, HIDWORD (address), LODWORD (address))); /* Perform the memory read or write */ switch (function) { case ACPI_READ_ADR_SPACE: switch (bit_width) { case 8: *value = (u32)* (u8 *) logical_addr_ptr; break; case 16: MOVE_UNALIGNED16_TO_32 (value, logical_addr_ptr); break; case 32: MOVE_UNALIGNED32_TO_32 (value, logical_addr_ptr); break; } break; case ACPI_WRITE_ADR_SPACE: switch (bit_width) { case 8: *(u8 *) logical_addr_ptr = (u8) *value; break; case 16: MOVE_UNALIGNED16_TO_16 (logical_addr_ptr, value); break; case 32: MOVE_UNALIGNED32_TO_32 (logical_addr_ptr, value); break; } break; default: status = AE_BAD_PARAMETER; break; } return_ACPI_STATUS (status); }
static int __init pvh_setup_acpi(struct domain *d, paddr_t start_info) { unsigned long pfn, nr_pages; paddr_t madt_paddr, xsdt_paddr, rsdp_paddr; unsigned int i; int rc; struct acpi_table_rsdp *native_rsdp, rsdp = { .signature = ACPI_SIG_RSDP, .revision = 2, .length = sizeof(rsdp), }; /* Scan top-level tables and add their regions to the guest memory map. */ for( i = 0; i < acpi_gbl_root_table_list.count; i++ ) { const char *sig = acpi_gbl_root_table_list.tables[i].signature.ascii; unsigned long addr = acpi_gbl_root_table_list.tables[i].address; unsigned long size = acpi_gbl_root_table_list.tables[i].length; /* * Make sure the original MADT is also mapped, so that Dom0 can * properly access the data returned by _MAT methods in case it's * re-using MADT memory. */ if ( strncmp(sig, ACPI_SIG_MADT, ACPI_NAME_SIZE) ? pvh_acpi_table_allowed(sig) : !acpi_memory_banned(addr, size) ) pvh_add_mem_range(d, addr, addr + size, E820_ACPI); } /* Identity map ACPI e820 regions. */ for ( i = 0; i < d->arch.nr_e820; i++ ) { if ( d->arch.e820[i].type != E820_ACPI && d->arch.e820[i].type != E820_NVS ) continue; pfn = PFN_DOWN(d->arch.e820[i].addr); nr_pages = PFN_UP((d->arch.e820[i].addr & ~PAGE_MASK) + d->arch.e820[i].size); rc = modify_identity_mmio(d, pfn, nr_pages, true); if ( rc ) { printk("Failed to map ACPI region [%#lx, %#lx) into Dom0 memory map\n", pfn, pfn + nr_pages); return rc; } } rc = pvh_setup_acpi_madt(d, &madt_paddr); if ( rc ) return rc; rc = pvh_setup_acpi_xsdt(d, madt_paddr, &xsdt_paddr); if ( rc ) return rc; /* Craft a custom RSDP. */ native_rsdp = acpi_os_map_memory(acpi_os_get_root_pointer(), sizeof(rsdp)); if ( !native_rsdp ) { printk("Failed to map native RSDP\n"); return -ENOMEM; } memcpy(rsdp.oem_id, native_rsdp->oem_id, sizeof(rsdp.oem_id)); acpi_os_unmap_memory(native_rsdp, sizeof(rsdp)); rsdp.xsdt_physical_address = xsdt_paddr; /* * Calling acpi_tb_checksum here is a layering violation, but * introducing a wrapper for such simple usage seems overkill. */ rsdp.checksum -= acpi_tb_checksum(ACPI_CAST_PTR(u8, &rsdp), ACPI_RSDP_REV0_SIZE); rsdp.extended_checksum -= acpi_tb_checksum(ACPI_CAST_PTR(u8, &rsdp), sizeof(rsdp)); /* * Place the new RSDP in guest memory space. * * NB: this RSDP is not going to replace the original RSDP, which should * still be accessible to the guest. However that RSDP is going to point to * the native RSDT, and should not be used for the Dom0 kernel's boot * purposes (we keep it visible for post boot access). */ if ( pvh_steal_ram(d, sizeof(rsdp), 0, GB(4), &rsdp_paddr) ) { printk("Unable to allocate guest RAM for RSDP\n"); return -ENOMEM; } /* Mark this region as E820_ACPI. */ if ( pvh_add_mem_range(d, rsdp_paddr, rsdp_paddr + sizeof(rsdp), E820_ACPI) ) printk("Unable to add RSDP region to memory map\n"); /* Copy RSDP into guest memory. */ rc = hvm_copy_to_guest_phys(rsdp_paddr, &rsdp, sizeof(rsdp), d->vcpu[0]); if ( rc ) { printk("Unable to copy RSDP into guest memory\n"); return rc; } /* Copy RSDP address to start_info. */ rc = hvm_copy_to_guest_phys(start_info + offsetof(struct hvm_start_info, rsdp_paddr), &rsdp_paddr, sizeof(((struct hvm_start_info *) 0)->rsdp_paddr), d->vcpu[0]); if ( rc ) { printk("Unable to copy RSDP into guest memory\n"); return rc; } return 0; } int __init dom0_construct_pvh(struct domain *d, const module_t *image, unsigned long image_headroom, module_t *initrd, void *(*bootstrap_map)(const module_t *), char *cmdline) { paddr_t entry, start_info; int rc; printk("** Building a PVH Dom0 **\n"); iommu_hwdom_init(d); rc = pvh_setup_p2m(d); if ( rc ) { printk("Failed to setup Dom0 physical memory map\n"); return rc; } rc = pvh_load_kernel(d, image, image_headroom, initrd, bootstrap_map(image), cmdline, &entry, &start_info); if ( rc ) { printk("Failed to load Dom0 kernel\n"); return rc; } rc = pvh_setup_cpus(d, entry, start_info); if ( rc ) { printk("Failed to setup Dom0 CPUs: %d\n", rc); return rc; } rc = pvh_setup_acpi(d, start_info); if ( rc ) { printk("Failed to setup Dom0 ACPI tables: %d\n", rc); return rc; } panic("Building a PVHv2 Dom0 is not yet supported."); return 0; }
static int __init pvh_setup_acpi_xsdt(struct domain *d, paddr_t madt_addr, paddr_t *addr) { struct acpi_table_xsdt *xsdt; struct acpi_table_header *table; struct acpi_table_rsdp *rsdp; unsigned long size = sizeof(*xsdt); unsigned int i, j, num_tables = 0; paddr_t xsdt_paddr; int rc; /* * Restore original DMAR table signature, we are going to filter it from * the new XSDT that is presented to the guest, so it is no longer * necessary to have it's signature zapped. */ acpi_dmar_reinstate(); /* Count the number of tables that will be added to the XSDT. */ for( i = 0; i < acpi_gbl_root_table_list.count; i++ ) { const char *sig = acpi_gbl_root_table_list.tables[i].signature.ascii; if ( pvh_acpi_table_allowed(sig) ) num_tables++; } /* * No need to add or subtract anything because struct acpi_table_xsdt * includes one array slot already, and we have filtered out the original * MADT and we are going to add a custom built MADT. */ size += num_tables * sizeof(xsdt->table_offset_entry[0]); xsdt = xzalloc_bytes(size); if ( !xsdt ) { printk("Unable to allocate memory for XSDT table\n"); rc = -ENOMEM; goto out; } /* Copy the native XSDT table header. */ rsdp = acpi_os_map_memory(acpi_os_get_root_pointer(), sizeof(*rsdp)); if ( !rsdp ) { printk("Unable to map RSDP\n"); rc = -EINVAL; goto out; } xsdt_paddr = rsdp->xsdt_physical_address; acpi_os_unmap_memory(rsdp, sizeof(*rsdp)); table = acpi_os_map_memory(xsdt_paddr, sizeof(*table)); if ( !table ) { printk("Unable to map XSDT\n"); rc = -EINVAL; goto out; } xsdt->header = *table; acpi_os_unmap_memory(table, sizeof(*table)); /* Add the custom MADT. */ xsdt->table_offset_entry[0] = madt_addr; /* Copy the addresses of the rest of the allowed tables. */ for( i = 0, j = 1; i < acpi_gbl_root_table_list.count; i++ ) { const char *sig = acpi_gbl_root_table_list.tables[i].signature.ascii; if ( pvh_acpi_table_allowed(sig) ) xsdt->table_offset_entry[j++] = acpi_gbl_root_table_list.tables[i].address; } xsdt->header.revision = 1; xsdt->header.length = size; /* * Calling acpi_tb_checksum here is a layering violation, but * introducing a wrapper for such simple usage seems overkill. */ xsdt->header.checksum -= acpi_tb_checksum(ACPI_CAST_PTR(u8, xsdt), size); /* Place the new XSDT in guest memory space. */ if ( pvh_steal_ram(d, size, 0, GB(4), addr) ) { printk("Unable to find guest RAM for XSDT\n"); rc = -ENOMEM; goto out; } /* Mark this region as E820_ACPI. */ if ( pvh_add_mem_range(d, *addr, *addr + size, E820_ACPI) ) printk("Unable to add XSDT region to memory map\n"); rc = hvm_copy_to_guest_phys(*addr, xsdt, size, d->vcpu[0]); if ( rc ) { printk("Unable to copy XSDT into guest memory\n"); goto out; } rc = 0; out: xfree(xsdt); return rc; }
acpi_status acpi_ex_system_memory_space_handler ( u32 function, acpi_physical_address address, u32 bit_width, acpi_integer *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; void *logical_addr_ptr = NULL; struct acpi_mem_space_context *mem_info = region_context; u32 length; acpi_size window_size; #ifndef ACPI_MISALIGNED_TRANSFERS u32 remainder; #endif ACPI_FUNCTION_TRACE ("ex_system_memory_space_handler"); /* Validate and translate the bit width */ switch (bit_width) { case 8: length = 1; break; case 16: length = 2; break; case 32: length = 4; break; case 64: length = 8; break; default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid system_memory width %d\n", bit_width)); return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } #ifndef ACPI_MISALIGNED_TRANSFERS /* * Hardware does not support non-aligned data transfers, we must verify * the request. */ (void) acpi_ut_short_divide ((acpi_integer) address, length, NULL, &remainder); if (remainder != 0) { return_ACPI_STATUS (AE_AML_ALIGNMENT); } #endif /* * Does the request fit into the cached memory mapping? * Is 1) Address below the current mapping? OR * 2) Address beyond the current mapping? */ if ((address < mem_info->mapped_physical_address) || (((acpi_integer) address + length) > ((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; * Delete the existing mapping and create a new one. */ if (mem_info->mapped_length) { /* Valid mapping, delete it */ acpi_os_unmap_memory (mem_info->mapped_logical_address, mem_info->mapped_length); } /* * Don't attempt to map memory beyond the end of the region, and * constrain the maximum mapping size to something reasonable. */ window_size = (acpi_size) ((mem_info->address + mem_info->length) - address); if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) { window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE; } /* Create a new mapping starting at the address given */ status = acpi_os_map_memory (address, window_size, (void **) &mem_info->mapped_logical_address); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n", ACPI_FORMAT_UINT64 (address), (u32) window_size)); mem_info->mapped_length = 0; return_ACPI_STATUS (status); } /* Save the physical address and mapping size */ mem_info->mapped_physical_address = address; mem_info->mapped_length = window_size; } /* * Generate a logical pointer corresponding to the address we want to * access */ logical_addr_ptr = mem_info->mapped_logical_address + ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, ACPI_FORMAT_UINT64 (address))); /* * Perform the memory read or write * * Note: For machines that do not support non-aligned transfers, the target * address was checked for alignment above. We do not attempt to break the * transfer up into smaller (byte-size) chunks because the AML specifically * asked for a transfer width that the hardware may require. */ switch (function) { case ACPI_READ: *value = 0; switch (bit_width) { case 8: *value = (acpi_integer) *((u8 *) logical_addr_ptr); break; case 16: *value = (acpi_integer) *((u16 *) logical_addr_ptr); break; case 32: *value = (acpi_integer) *((u32 *) logical_addr_ptr); break; #if ACPI_MACHINE_WIDTH != 16 case 64: *value = (acpi_integer) *((u64 *) logical_addr_ptr); break; #endif default: /* bit_width was already validated */ break; } break; case ACPI_WRITE: switch (bit_width) { case 8: *(u8 *) logical_addr_ptr = (u8) *value; break; case 16: *(u16 *) logical_addr_ptr = (u16) *value; break; case 32: *(u32 *) logical_addr_ptr = (u32) *value; break; #if ACPI_MACHINE_WIDTH != 16 case 64: *(u64 *) logical_addr_ptr = (u64) *value; break; #endif default: /* bit_width was already validated */ break; } break; default: status = AE_BAD_PARAMETER; break; } return_ACPI_STATUS (status); }
acpi_status acpi_find_root_pointer(acpi_size *table_address) { u8 *table_ptr; u8 *mem_rover; u32 physical_address; ACPI_FUNCTION_TRACE(acpi_find_root_pointer); /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ table_ptr = acpi_os_map_memory((acpi_physical_address) ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH); if (!table_ptr) { ACPI_ERROR((AE_INFO, "Could not map memory at 0x%8.8X for length %u", ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); return_ACPI_STATUS(AE_NO_MEMORY); } ACPI_MOVE_16_TO_32(&physical_address, table_ptr); /* Convert segment part to physical address */ physical_address <<= 4; acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH); /* EBDA present? */ if (physical_address > 0x400) { /* * 1b) Search EBDA paragraphs (EBDA is required to be a * minimum of 1K length) */ table_ptr = acpi_os_map_memory((acpi_physical_address) physical_address, ACPI_EBDA_WINDOW_SIZE); if (!table_ptr) { ACPI_ERROR((AE_INFO, "Could not map memory at 0x%8.8X for length %u", physical_address, ACPI_EBDA_WINDOW_SIZE)); return_ACPI_STATUS(AE_NO_MEMORY); } mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_EBDA_WINDOW_SIZE); acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE); if (mem_rover) { /* Return the physical address */ physical_address += (u32) ACPI_PTR_DIFF(mem_rover, table_ptr); *table_address = physical_address; return_ACPI_STATUS(AE_OK); } } /* * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ table_ptr = acpi_os_map_memory((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE); if (!table_ptr) { ACPI_ERROR((AE_INFO, "Could not map memory at 0x%8.8X for length %u", ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); return_ACPI_STATUS(AE_NO_MEMORY); } mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); if (mem_rover) { /* Return the physical address */ physical_address = (u32) (ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF(mem_rover, table_ptr)); *table_address = physical_address; return_ACPI_STATUS(AE_OK); } /* A valid RSDP was not found */ ACPI_BIOS_ERROR((AE_INFO, "A valid RSDP was not found")); return_ACPI_STATUS(AE_NOT_FOUND); }
/******************************************************************************* * * FUNCTION: acpi_ex_system_memory_space_handler * * PARAMETERS: Function - Read or Write operation * Address - Where in the space to read or write * bit_width - Field width in bits (8, 16, or 32) * Value - Pointer to in or out value * handler_context - Pointer to Handler's context * region_context - Pointer to context specific to the * accessed region * * RETURN: Status * * DESCRIPTION: Handler for the System Memory address space (Op Region) * ******************************************************************************/ acpi_status acpi_ex_system_memory_space_handler(u32 function, acpi_physical_address address, u32 bit_width, u64 *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; void *logical_addr_ptr = NULL; struct acpi_mem_space_context *mem_info = region_context; u32 length; acpi_size map_length; acpi_size page_boundary_map_length; #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED u32 remainder; #endif ACPI_FUNCTION_TRACE(ex_system_memory_space_handler); /* Validate and translate the bit width */ switch (bit_width) { case 8: length = 1; break; case 16: length = 2; break; case 32: length = 4; break; case 64: length = 8; break; default: ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u", bit_width)); return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED /* * Hardware does not support non-aligned data transfers, we must verify * the request. */ (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder); if (remainder != 0) { return_ACPI_STATUS(AE_AML_ALIGNMENT); } #endif /* * Does the request fit into the cached memory mapping? * Is 1) Address below the current mapping? OR * 2) Address beyond the current mapping? */ if ((address < mem_info->mapped_physical_address) || (((u64) address + length) > ((u64) mem_info->mapped_physical_address + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; * Delete the existing mapping and create a new one. */ if (mem_info->mapped_length) { /* Valid mapping, delete it */ acpi_os_unmap_memory(mem_info->mapped_logical_address, mem_info->mapped_length); } /* * Attempt to map from the requested address to the end of the region. * However, we will never map more than one page, nor will we cross * a page boundary. */ map_length = (acpi_size) ((mem_info->address + mem_info->length) - address); /* * If mapping the entire remaining portion of the region will cross * a page boundary, just map up to the page boundary, do not cross. * On some systems, crossing a page boundary while mapping regions * can cause warnings if the pages have different attributes * due to resource management */ page_boundary_map_length = ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address; if (!page_boundary_map_length) { page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE; } if (map_length > page_boundary_map_length) { map_length = page_boundary_map_length; } /* Create a new mapping starting at the address given */ mem_info->mapped_logical_address = acpi_os_map_memory((acpi_physical_address) address, map_length); if (!mem_info->mapped_logical_address) { ACPI_ERROR((AE_INFO, "Could not map memory at 0x%8.8X%8.8X, size %u", ACPI_FORMAT_NATIVE_UINT(address), (u32) map_length)); mem_info->mapped_length = 0; return_ACPI_STATUS(AE_NO_MEMORY); } /* Save the physical address and mapping size */ mem_info->mapped_physical_address = address; mem_info->mapped_length = map_length; } /* * Generate a logical pointer corresponding to the address we want to * access */ logical_addr_ptr = mem_info->mapped_logical_address + ((u64) address - (u64) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n", bit_width, function, ACPI_FORMAT_NATIVE_UINT(address))); /* * Perform the memory read or write * * Note: For machines that do not support non-aligned transfers, the target * address was checked for alignment above. We do not attempt to break the * transfer up into smaller (byte-size) chunks because the AML specifically * asked for a transfer width that the hardware may require. */ switch (function) { case ACPI_READ: *value = 0; switch (bit_width) { case 8: *value = (u64) ACPI_GET8(logical_addr_ptr); break; case 16: *value = (u64) ACPI_GET16(logical_addr_ptr); break; case 32: *value = (u64) ACPI_GET32(logical_addr_ptr); break; case 64: *value = (u64) ACPI_GET64(logical_addr_ptr); break; default: /* bit_width was already validated */ break; } break; case ACPI_WRITE: switch (bit_width) { case 8: ACPI_SET8(logical_addr_ptr) = (u8) * value; break; case 16: ACPI_SET16(logical_addr_ptr) = (u16) * value; break; case 32: ACPI_SET32(logical_addr_ptr) = (u32) * value; break; case 64: ACPI_SET64(logical_addr_ptr) = (u64) * value; break; default: /* bit_width was already validated */ break; } break; default: status = AE_BAD_PARAMETER; break; } return_ACPI_STATUS(status); }
acpi_status acpi_tb_find_rsdp ( struct acpi_table_desc *table_info, u32 flags) { u8 *table_ptr; u8 *mem_rover; u64 phys_addr; acpi_status status = AE_OK; ACPI_FUNCTION_TRACE ("tb_find_rsdp"); /* * Scan supports either 1) Logical addressing or 2) Physical addressing */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { /* * 1) Search EBDA (low memory) paragraphs */ status = acpi_os_map_memory ((u64) ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE, (void *) &table_ptr); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE)); return_ACPI_STATUS (status); } mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_LO_RSDP_WINDOW_SIZE); acpi_os_unmap_memory (table_ptr, ACPI_LO_RSDP_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ phys_addr = ACPI_LO_RSDP_WINDOW_BASE; phys_addr += ACPI_PTR_DIFF (mem_rover,table_ptr); table_info->physical_address = phys_addr; return_ACPI_STATUS (AE_OK); } /* * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h */ status = acpi_os_map_memory ((u64) ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE, (void *) &table_ptr); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); return_ACPI_STATUS (status); } mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); acpi_os_unmap_memory (table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ phys_addr = ACPI_HI_RSDP_WINDOW_BASE; phys_addr += ACPI_PTR_DIFF (mem_rover, table_ptr); table_info->physical_address = phys_addr; return_ACPI_STATUS (AE_OK); } } /* * Physical addressing */ else { /* * 1) Search EBDA (low memory) paragraphs */ mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_LO_RSDP_WINDOW_BASE), ACPI_LO_RSDP_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ table_info->physical_address = ACPI_TO_INTEGER (mem_rover); return_ACPI_STATUS (AE_OK); } /* * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h */ mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), ACPI_HI_RSDP_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ table_info->physical_address = ACPI_TO_INTEGER (mem_rover); return_ACPI_STATUS (AE_OK); } } /* RSDP signature was not found */ return_ACPI_STATUS (AE_NOT_FOUND); }
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); }
static int __init extlog_init(void) { struct extlog_l1_head *l1_head; void __iomem *extlog_l1_hdr; size_t l1_hdr_size; struct resource *r; u64 cap; int rc; rc = -ENODEV; rdmsrl(MSR_IA32_MCG_CAP, cap); if (!(cap & MCG_ELOG_P)) return rc; if (!extlog_get_l1addr()) return rc; rc = -EINVAL; /* get L1 header to fetch necessary information */ l1_hdr_size = sizeof(struct extlog_l1_head); r = request_mem_region(l1_dirbase, l1_hdr_size, "L1 DIR HDR"); if (!r) { pr_warn(FW_BUG EMCA_BUG, (unsigned long long)l1_dirbase, (unsigned long long)l1_dirbase + l1_hdr_size); goto err; } extlog_l1_hdr = acpi_os_map_memory(l1_dirbase, l1_hdr_size); l1_head = (struct extlog_l1_head *)extlog_l1_hdr; l1_size = l1_head->total_len; l1_percpu_entry = l1_head->entries; elog_base = l1_head->elog_base; elog_size = l1_head->elog_len; acpi_os_unmap_memory(extlog_l1_hdr, l1_hdr_size); release_mem_region(l1_dirbase, l1_hdr_size); /* remap L1 header again based on completed information */ r = request_mem_region(l1_dirbase, l1_size, "L1 Table"); if (!r) { pr_warn(FW_BUG EMCA_BUG, (unsigned long long)l1_dirbase, (unsigned long long)l1_dirbase + l1_size); goto err; } extlog_l1_addr = acpi_os_map_memory(l1_dirbase, l1_size); l1_entry_base = (u64 *)((u8 *)extlog_l1_addr + l1_hdr_size); /* remap elog table */ r = request_mem_region(elog_base, elog_size, "Elog Table"); if (!r) { pr_warn(FW_BUG EMCA_BUG, (unsigned long long)elog_base, (unsigned long long)elog_base + elog_size); goto err_release_l1_dir; } elog_addr = acpi_os_map_memory(elog_base, elog_size); rc = -ENOMEM; /* allocate buffer to save elog record */ elog_buf = kmalloc(ELOG_ENTRY_LEN, GFP_KERNEL); if (elog_buf == NULL) goto err_release_elog; mce_register_decode_chain(&extlog_mce_dec); /* enable OS to be involved to take over management from BIOS */ ((struct extlog_l1_head *)extlog_l1_addr)->flags |= FLAG_OS_OPTIN; return 0; err_release_elog: if (elog_addr) acpi_os_unmap_memory(elog_addr, elog_size); release_mem_region(elog_base, elog_size); err_release_l1_dir: if (extlog_l1_addr) acpi_os_unmap_memory(extlog_l1_addr, l1_size); release_mem_region(l1_dirbase, l1_size); err: pr_warn(FW_BUG "Extended error log disabled because of problems parsing f/w tables\n"); return rc; }