FreeBSD/sys/x86/x86/local_apic.c
/*
 * Map the local APIC and setup necessary interrupt vectors.
 */
Map the local APIC and setup necessary interrupt vectors.
Map the local APIC and setup necessary interrupt vectors .
static void
native_lapic_init(vm_paddr_t addr)
{
#ifdef SMP
	uint64_t r, r1, r2, rx;
#endif
	uint32_t ver;
	u_int regs[4];
	int i, arat;
	KASSERT(trunc_page(addr) == addr,
	    ("local APIC not aligned on a page boundary"));
	lapic_paddr = addr;
	lapic_map = pmap_mapdev(addr, PAGE_SIZE);
	if (x2apic_mode) {
		native_lapic_enable_x2apic();
		lapic_map = NULL;
	}
	setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_APIC, SEL_KPL,
	    GSEL_APIC);
	lapic_enable();
	PCPU_SET(apic_id, lapic_id());
	setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_APIC, SEL_KPL, GSEL_APIC);
	setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_APIC, SEL_KPL, GSEL_APIC);
	setidt(APIC_CMC_INT, IDTVEC(cmcint), SDT_APICT, SEL_KPL, GSEL_APIC);
	if ((resource_int_value("apic", 0, "clock", &i) != 0 || i != 0)) {
		arat = 0;
		if (cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high >= 6) {
			do_cpuid(0x06, regs);
			if ((regs[0] & CPUTPM1_ARAT) != 0)
				arat = 1;
		}
		bzero(&lapic_et, sizeof(lapic_et));
		lapic_et.et_name = "LAPIC";
		lapic_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
		    ET_FLAGS_PERCPU;
		lapic_et.et_quality = 600;
		if (!arat) {
			lapic_et.et_flags |= ET_FLAGS_C3STOP;
			lapic_et.et_quality -= 200;
		} else if ((cpu_feature & CPUID_TSC) != 0 &&
		    (cpu_feature2 & CPUID2_TSCDLT) != 0 &&
		    tsc_is_invariant && tsc_freq != 0) {
			lapic_timer_tsc_deadline = 1;
			TUNABLE_INT_FETCH("hw.lapic_tsc_deadline",
			    &lapic_timer_tsc_deadline);
		}
		lapic_et.et_frequency = 0;
		lapic_et.et_min_period = 0x00001000LL;
		lapic_et.et_max_period = SBT_1S;
		lapic_et.et_start = lapic_et_start;
		lapic_et.et_stop = lapic_et_stop;
		lapic_et.et_priv = NULL;
		et_register(&lapic_et);
	}
	ver = lapic_read32(LAPIC_VERSION);
	if ((ver & APIC_VER_EOI_SUPPRESSION) != 0) {
		lapic_eoi_suppression = 1;
		if (vm_guest == VM_GUEST_VM &&
		    !strcmp(hv_vendor, "KVMKVMKVM")) {
			if (bootverbose)
				printf(
		       "KVM -- disabling lapic eoi suppression\n");
			lapic_eoi_suppression = 0;
		}
		TUNABLE_INT_FETCH("hw.lapic_eoi_suppression",
		    &lapic_eoi_suppression);
	}
#ifdef SMP
#define	LOOPS	100000
	KASSERT((cpu_feature & CPUID_TSC) != 0 && tsc_freq != 0,
	    ("TSC not initialized"));
	if (!x2apic_mode) {
		r = rdtsc();
		for (rx = 0; rx < LOOPS; rx++) {
			(void)lapic_read_icr_lo();
			ia32_pause();
		}
		r = rdtsc() - r;
		r1 = tsc_freq * LOOPS;
		r2 = r * 1000000;
		lapic_ipi_wait_mult = r1 >= r2 ? r1 / r2 : 1;
		if (bootverbose) {
			printf("LAPIC: ipi_wait() us multiplier %ju (r %ju "
			    "tsc %ju)\n", (uintmax_t)lapic_ipi_wait_mult,
			    (uintmax_t)r, (uintmax_t)tsc_freq);
		}
	}
#undef LOOPS
#endif 
}
static void native_lapic_init ( vm_paddr_t addr ) { #ifdef SMP uint64_t r , r1 , r2 , rx ; #endif uint32_t ver ; u_int regs [ 4 ] ; int i , arat ; KASSERT ( trunc_page ( addr ) == addr , ( " " ) ) ; lapic_paddr = addr ; lapic_map = pmap_mapdev ( addr , PAGE_SIZE ) ; if ( x2apic_mode ) { native_lapic_enable_x2apic ( ) ; lapic_map = NULL ; } setidt ( APIC_SPURIOUS_INT , IDTVEC ( spuriousint ) , SDT_APIC , SEL_KPL , GSEL_APIC ) ; lapic_enable ( ) ; PCPU_SET ( apic_id , lapic_id ( ) ) ; setidt ( APIC_TIMER_INT , IDTVEC ( timerint ) , SDT_APIC , SEL_KPL , GSEL_APIC ) ; setidt ( APIC_ERROR_INT , IDTVEC ( errorint ) , SDT_APIC , SEL_KPL , GSEL_APIC ) ; setidt ( APIC_CMC_INT , IDTVEC ( cmcint ) , SDT_APICT , SEL_KPL , GSEL_APIC ) ; if ( ( resource_int_value ( " " , 0 , " " , & i ) != 0 || i != 0 ) ) { arat = 0 ; if ( cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high >= 6 ) { do_cpuid ( 0x06 , regs ) ; if ( ( regs [ 0 ] & CPUTPM1_ARAT ) != 0 ) arat = 1 ; } bzero ( & lapic_et , sizeof ( lapic_et ) ) ; lapic_et . et_name = " " ; lapic_et . et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU ; lapic_et . et_quality = 600 ; if ( ! arat ) { lapic_et . et_flags |= ET_FLAGS_C3STOP ; lapic_et . et_quality -= 200 ; } else if ( ( cpu_feature & CPUID_TSC ) != 0 && ( cpu_feature2 & CPUID2_TSCDLT ) != 0 && tsc_is_invariant && tsc_freq != 0 ) { lapic_timer_tsc_deadline = 1 ; TUNABLE_INT_FETCH ( " " , & lapic_timer_tsc_deadline ) ; } lapic_et . et_frequency = 0 ; lapic_et . et_min_period = 0x00001000LL ; lapic_et . et_max_period = SBT_1S ; lapic_et . et_start = lapic_et_start ; lapic_et . et_stop = lapic_et_stop ; lapic_et . et_priv = NULL ; et_register ( & lapic_et ) ; } ver = lapic_read32 ( LAPIC_VERSION ) ; if ( ( ver & APIC_VER_EOI_SUPPRESSION ) != 0 ) { lapic_eoi_suppression = 1 ; if ( vm_guest == VM_GUEST_VM && ! strcmp ( hv_vendor , " " ) ) { if ( bootverbose ) printf ( " \n " ) ; lapic_eoi_suppression = 0 ; } TUNABLE_INT_FETCH ( " " , & lapic_eoi_suppression ) ; } #ifdef SMP #define LOOPS 	100000 KASSERT ( ( cpu_feature & CPUID_TSC ) != 0 && tsc_freq != 0 , ( " " ) ) ; if ( ! x2apic_mode ) { r = rdtsc ( ) ; for ( rx = 0 ; rx < LOOPS ; rx ++ ) { ( void ) lapic_read_icr_lo ( ) ; ia32_pause ( ) ; } r = rdtsc ( ) - r ; r1 = tsc_freq * LOOPS ; r2 = r * 1000000 ; lapic_ipi_wait_mult = r1 >= r2 ? r1 / r2 : 1 ; if ( bootverbose ) { printf ( " " " \n " , ( uintmax_t ) lapic_ipi_wait_mult , ( uintmax_t ) r , ( uintmax_t ) tsc_freq ) ; } } #undef  LOOPS #endif }
Map the local APIC and setup necessary interrupt vectors.
Map the local APIC and setup necessary interrupt vectors .
/*
	 * Enable x2APIC mode if possible. Map the local APIC
	 * registers page.
	 *
	 * Keep the LAPIC registers page mapped uncached for x2APIC
	 * mode too, to have direct map page attribute set to
	 * uncached.  This is needed to work around CPU errata present
	 * on all Intel processors.
	 */ /* Setup the spurious interrupt handler. */ /* Perform basic initialization of the BSP's local APIC. */ /* Set BSP's per-CPU local APIC ID. */ /* Local APIC timer interrupt. */ /* Local APIC error interrupt. */ /* XXX: Thermal interrupt */ /* Local APIC CMCI. */ /* Intel CPUID 0x06 EAX[2] set if APIC timer runs in C3. */ /* We don't know frequency yet, so trying to guess. */ /*
	 * Set lapic_eoi_suppression after lapic_enable(), to not
	 * enable suppression in the hardware prematurely.  Note that
	 * we by default enable suppression even when system only has
	 * one IO-APIC, since EOI is broadcasted to all APIC agents,
	 * including CPUs, otherwise.
	 *
	 * It seems that at least some KVM versions report
	 * EOI_SUPPRESSION bit, but auto-EOI does not work.
	 */ /*
	 * Calibrate the busy loop waiting for IPI ack in xAPIC mode.
	 * lapic_ipi_wait_mult contains the number of iterations which
	 * approximately delay execution for 1 microsecond (the
	 * argument to native_lapic_ipi_wait() is in microseconds).
	 *
	 * We assume that TSC is present and already measured.
	 * Possible TSC frequency jumps are irrelevant to the
	 * calibration loop below, the CPU clock management code is
	 * not yet started, and we do not enter sleep states.
	 */ /* SMP */