Commit 81287ad6 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Dave Hansen
Browse files

x86/apic: Sanitize APIC address setup



Convert places which just write mp_lapic_addr and let them register the
local APIC address directly instead of relying on magic other code to do
so.

Add a WARN_ON() into register_lapic_address() which is raised when
register_lapic_address() is invoked more than once during boot.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: default avatarMichael Kelley <mikelley@microsoft.com>
Tested-by: default avatarSohil Mehta <sohil.mehta@intel.com>
Tested-by: Juergen Gross <jgross@suse.com> # Xen PV (dom0 and unpriv. guest)
parent 5a88f354
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ extern DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);

extern unsigned int boot_cpu_physical_apicid;
extern u8 boot_cpu_apic_version;
extern unsigned long mp_lapic_addr;

#ifdef CONFIG_X86_LOCAL_APIC
extern int smp_found_config;
+10 −19
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ static __init int setup_apicpmtimer(char *s)
__setup("apicpmtimer", setup_apicpmtimer);
#endif

unsigned long mp_lapic_addr __ro_after_init;
static unsigned long mp_lapic_addr __ro_after_init;
bool apic_is_disabled __ro_after_init;
/* Disable local APIC timer from the kernel commandline or via dmi quirk */
static int disable_apic_timer __initdata;
@@ -2009,12 +2009,12 @@ static bool __init detect_init_APIC(void)
		return false;
	}

	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
	register_lapic_address(APIC_DEFAULT_PHYS_BASE);
	return true;
}
#else

static bool __init apic_verify(void)
static bool __init apic_verify(unsigned long addr)
{
	u32 features, h, l;

@@ -2028,15 +2028,15 @@ static bool __init apic_verify(void)
		return false;
	}
	set_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;

	/* The BIOS may have set up the APIC at some other address */
	if (boot_cpu_data.x86 >= 6) {
		rdmsr(MSR_IA32_APICBASE, l, h);
		if (l & MSR_IA32_APICBASE_ENABLE)
			mp_lapic_addr = l & MSR_IA32_APICBASE_BASE;
			addr = l & MSR_IA32_APICBASE_BASE;
	}

	register_lapic_address(addr);
	pr_info("Found and enabled local APIC!\n");
	return true;
}
@@ -2063,7 +2063,7 @@ bool __init apic_force_enable(unsigned long addr)
			enabled_via_apicbase = 1;
		}
	}
	return apic_verify();
	return apic_verify(addr);
}

/*
@@ -2105,7 +2105,7 @@ static bool __init detect_init_APIC(void)
		if (!apic_force_enable(APIC_DEFAULT_PHYS_BASE))
			return false;
	} else {
		if (!apic_verify())
		if (!apic_verify(APIC_DEFAULT_PHYS_BASE))
			return false;
	}

@@ -2130,27 +2130,16 @@ void __init init_apic_mappings(void)
	if (x2apic_mode)
		return;

	/* If no local APIC can be found return early */
	if (!smp_found_config && !detect_init_APIC()) {
		/* lets NOP'ify apic operations */
		pr_info("APIC: disable apic facility\n");
		apic_disable();
	} else {
		apic_phys = mp_lapic_addr;

		/*
		 * If the system has ACPI MADT tables or MP info, the LAPIC
		 * address is already registered.
		 */
		if (!acpi_lapic && !smp_found_config)
			register_lapic_address(apic_phys);
	}
}

static __init void apic_set_fixmap(void)
{
	set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
	apic_mmio_base = APIC_BASE;
	apic_phys = apic_mmio_base = APIC_BASE;
	apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
		    apic_mmio_base, mp_lapic_addr);
	apic_read_boot_cpu_id(false);
@@ -2158,6 +2147,8 @@ static __init void apic_set_fixmap(void)

void __init register_lapic_address(unsigned long address)
{
	/* This should only happen once */
	WARN_ON_ONCE(mp_lapic_addr);
	mp_lapic_addr = address;

	if (!x2apic_mode)
+2 −9
Original line number Diff line number Diff line
@@ -374,11 +374,6 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
	int linttypes[2] = { mp_ExtINT, mp_NMI };
	int i;

	/*
	 * local APIC has default address
	 */
	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;

	/*
	 * 2 CPUs, numbered 0 & 1.
	 */
@@ -520,10 +515,8 @@ void __init default_get_smp_config(unsigned int early)
	 */
	if (mpf->feature1) {
		if (early) {
			/*
			 * local APIC has default address
			 */
			mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
			/* Local APIC has default address */
			register_lapic_address(APIC_DEFAULT_PHYS_BASE);
			goto out;
		}