cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

processor_core.c (9307B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2005 Intel Corporation
      4 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
      5 *
      6 *	Alex Chiang <achiang@hp.com>
      7 *	- Unified x86/ia64 implementations
      8 *
      9 * I/O APIC hotplug support
     10 *	Yinghai Lu <yinghai@kernel.org>
     11 *	Jiang Liu <jiang.liu@intel.com>
     12 */
     13#include <linux/export.h>
     14#include <linux/acpi.h>
     15#include <acpi/processor.h>
     16
     17static struct acpi_table_madt *get_madt_table(void)
     18{
     19	static struct acpi_table_madt *madt;
     20	static int read_madt;
     21
     22	if (!read_madt) {
     23		if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
     24					(struct acpi_table_header **)&madt)))
     25			madt = NULL;
     26		read_madt++;
     27	}
     28
     29	return madt;
     30}
     31
     32static int map_lapic_id(struct acpi_subtable_header *entry,
     33		 u32 acpi_id, phys_cpuid_t *apic_id)
     34{
     35	struct acpi_madt_local_apic *lapic =
     36		container_of(entry, struct acpi_madt_local_apic, header);
     37
     38	if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
     39		return -ENODEV;
     40
     41	if (lapic->processor_id != acpi_id)
     42		return -EINVAL;
     43
     44	*apic_id = lapic->id;
     45	return 0;
     46}
     47
     48static int map_x2apic_id(struct acpi_subtable_header *entry,
     49		int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
     50{
     51	struct acpi_madt_local_x2apic *apic =
     52		container_of(entry, struct acpi_madt_local_x2apic, header);
     53
     54	if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
     55		return -ENODEV;
     56
     57	if (device_declaration && (apic->uid == acpi_id)) {
     58		*apic_id = apic->local_apic_id;
     59		return 0;
     60	}
     61
     62	return -EINVAL;
     63}
     64
     65static int map_lsapic_id(struct acpi_subtable_header *entry,
     66		int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
     67{
     68	struct acpi_madt_local_sapic *lsapic =
     69		container_of(entry, struct acpi_madt_local_sapic, header);
     70
     71	if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
     72		return -ENODEV;
     73
     74	if (device_declaration) {
     75		if ((entry->length < 16) || (lsapic->uid != acpi_id))
     76			return -EINVAL;
     77	} else if (lsapic->processor_id != acpi_id)
     78		return -EINVAL;
     79
     80	*apic_id = (lsapic->id << 8) | lsapic->eid;
     81	return 0;
     82}
     83
     84/*
     85 * Retrieve the ARM CPU physical identifier (MPIDR)
     86 */
     87static int map_gicc_mpidr(struct acpi_subtable_header *entry,
     88		int device_declaration, u32 acpi_id, phys_cpuid_t *mpidr)
     89{
     90	struct acpi_madt_generic_interrupt *gicc =
     91	    container_of(entry, struct acpi_madt_generic_interrupt, header);
     92
     93	if (!(gicc->flags & ACPI_MADT_ENABLED))
     94		return -ENODEV;
     95
     96	/* device_declaration means Device object in DSDT, in the
     97	 * GIC interrupt model, logical processors are required to
     98	 * have a Processor Device object in the DSDT, so we should
     99	 * check device_declaration here
    100	 */
    101	if (device_declaration && (gicc->uid == acpi_id)) {
    102		*mpidr = gicc->arm_mpidr;
    103		return 0;
    104	}
    105
    106	return -EINVAL;
    107}
    108
    109static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
    110				   int type, u32 acpi_id)
    111{
    112	unsigned long madt_end, entry;
    113	phys_cpuid_t phys_id = PHYS_CPUID_INVALID;	/* CPU hardware ID */
    114
    115	if (!madt)
    116		return phys_id;
    117
    118	entry = (unsigned long)madt;
    119	madt_end = entry + madt->header.length;
    120
    121	/* Parse all entries looking for a match. */
    122
    123	entry += sizeof(struct acpi_table_madt);
    124	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
    125		struct acpi_subtable_header *header =
    126			(struct acpi_subtable_header *)entry;
    127		if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
    128			if (!map_lapic_id(header, acpi_id, &phys_id))
    129				break;
    130		} else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
    131			if (!map_x2apic_id(header, type, acpi_id, &phys_id))
    132				break;
    133		} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
    134			if (!map_lsapic_id(header, type, acpi_id, &phys_id))
    135				break;
    136		} else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
    137			if (!map_gicc_mpidr(header, type, acpi_id, &phys_id))
    138				break;
    139		}
    140		entry += header->length;
    141	}
    142	return phys_id;
    143}
    144
    145phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
    146{
    147	struct acpi_table_madt *madt = NULL;
    148	phys_cpuid_t rv;
    149
    150	acpi_get_table(ACPI_SIG_MADT, 0,
    151		       (struct acpi_table_header **)&madt);
    152	if (!madt)
    153		return PHYS_CPUID_INVALID;
    154
    155	rv = map_madt_entry(madt, 1, acpi_id);
    156
    157	acpi_put_table((struct acpi_table_header *)madt);
    158
    159	return rv;
    160}
    161
    162static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
    163{
    164	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
    165	union acpi_object *obj;
    166	struct acpi_subtable_header *header;
    167	phys_cpuid_t phys_id = PHYS_CPUID_INVALID;
    168
    169	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
    170		goto exit;
    171
    172	if (!buffer.length || !buffer.pointer)
    173		goto exit;
    174
    175	obj = buffer.pointer;
    176	if (obj->type != ACPI_TYPE_BUFFER ||
    177	    obj->buffer.length < sizeof(struct acpi_subtable_header)) {
    178		goto exit;
    179	}
    180
    181	header = (struct acpi_subtable_header *)obj->buffer.pointer;
    182	if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
    183		map_lapic_id(header, acpi_id, &phys_id);
    184	else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
    185		map_lsapic_id(header, type, acpi_id, &phys_id);
    186	else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
    187		map_x2apic_id(header, type, acpi_id, &phys_id);
    188	else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
    189		map_gicc_mpidr(header, type, acpi_id, &phys_id);
    190
    191exit:
    192	kfree(buffer.pointer);
    193	return phys_id;
    194}
    195
    196phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
    197{
    198	phys_cpuid_t phys_id;
    199
    200	phys_id = map_mat_entry(handle, type, acpi_id);
    201	if (invalid_phys_cpuid(phys_id))
    202		phys_id = map_madt_entry(get_madt_table(), type, acpi_id);
    203
    204	return phys_id;
    205}
    206EXPORT_SYMBOL_GPL(acpi_get_phys_id);
    207
    208int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
    209{
    210#ifdef CONFIG_SMP
    211	int i;
    212#endif
    213
    214	if (invalid_phys_cpuid(phys_id)) {
    215		/*
    216		 * On UP processor, there is no _MAT or MADT table.
    217		 * So above phys_id is always set to PHYS_CPUID_INVALID.
    218		 *
    219		 * BIOS may define multiple CPU handles even for UP processor.
    220		 * For example,
    221		 *
    222		 * Scope (_PR)
    223		 * {
    224		 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
    225		 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
    226		 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
    227		 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
    228		 * }
    229		 *
    230		 * Ignores phys_id and always returns 0 for the processor
    231		 * handle with acpi id 0 if nr_cpu_ids is 1.
    232		 * This should be the case if SMP tables are not found.
    233		 * Return -EINVAL for other CPU's handle.
    234		 */
    235		if (nr_cpu_ids <= 1 && acpi_id == 0)
    236			return acpi_id;
    237		else
    238			return -EINVAL;
    239	}
    240
    241#ifdef CONFIG_SMP
    242	for_each_possible_cpu(i) {
    243		if (cpu_physical_id(i) == phys_id)
    244			return i;
    245	}
    246#else
    247	/* In UP kernel, only processor 0 is valid */
    248	if (phys_id == 0)
    249		return phys_id;
    250#endif
    251	return -ENODEV;
    252}
    253
    254int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
    255{
    256	phys_cpuid_t phys_id;
    257
    258	phys_id = acpi_get_phys_id(handle, type, acpi_id);
    259
    260	return acpi_map_cpuid(phys_id, acpi_id);
    261}
    262EXPORT_SYMBOL_GPL(acpi_get_cpuid);
    263
    264#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
    265static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
    266			 u64 *phys_addr, int *ioapic_id)
    267{
    268	struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
    269
    270	if (ioapic->global_irq_base != gsi_base)
    271		return 0;
    272
    273	*phys_addr = ioapic->address;
    274	*ioapic_id = ioapic->id;
    275	return 1;
    276}
    277
    278static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
    279{
    280	struct acpi_subtable_header *hdr;
    281	unsigned long madt_end, entry;
    282	struct acpi_table_madt *madt;
    283	int apic_id = -1;
    284
    285	madt = get_madt_table();
    286	if (!madt)
    287		return apic_id;
    288
    289	entry = (unsigned long)madt;
    290	madt_end = entry + madt->header.length;
    291
    292	/* Parse all entries looking for a match. */
    293	entry += sizeof(struct acpi_table_madt);
    294	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
    295		hdr = (struct acpi_subtable_header *)entry;
    296		if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
    297		    get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
    298			break;
    299		else
    300			entry += hdr->length;
    301	}
    302
    303	return apic_id;
    304}
    305
    306static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
    307				  u64 *phys_addr)
    308{
    309	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
    310	struct acpi_subtable_header *header;
    311	union acpi_object *obj;
    312	int apic_id = -1;
    313
    314	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
    315		goto exit;
    316
    317	if (!buffer.length || !buffer.pointer)
    318		goto exit;
    319
    320	obj = buffer.pointer;
    321	if (obj->type != ACPI_TYPE_BUFFER ||
    322	    obj->buffer.length < sizeof(struct acpi_subtable_header))
    323		goto exit;
    324
    325	header = (struct acpi_subtable_header *)obj->buffer.pointer;
    326	if (header->type == ACPI_MADT_TYPE_IO_APIC)
    327		get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
    328
    329exit:
    330	kfree(buffer.pointer);
    331	return apic_id;
    332}
    333
    334/**
    335 * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base
    336 * @handle:	ACPI object for IOAPIC device
    337 * @gsi_base:	GSI base to match with
    338 * @phys_addr:	Pointer to store physical address of matching IOAPIC record
    339 *
    340 * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search
    341 * for an ACPI IOAPIC record matching @gsi_base.
    342 * Return IOAPIC id and store physical address in @phys_addr if found a match,
    343 * otherwise return <0.
    344 */
    345int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
    346{
    347	int apic_id;
    348
    349	apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
    350	if (apic_id == -1)
    351		apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);
    352
    353	return apic_id;
    354}
    355#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */