/* * Copyright 2017, Data61 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) * ABN 41 687 119 230. * * This software may be distributed and modified according to the terms of * the GNU General Public License version 2. Note that NO WARRANTY is provided. * See "LICENSE_GPLv2.txt" for details. * * @TAG(DATA61_GPL) */ #include #include #include #ifdef CONFIG_XAPIC #ifdef CONFIG_USE_LOGICAL_IDS /* using flat cluster mode we only support 8 cores */ compile_assert(number_of_cores_invalid_for_logical_ids, CONFIG_MAX_NUM_NODES <= 8) BOOT_CODE static void init_xapic_ldr(void) { uint32_t ldr; apic_write_reg(APIC_DEST_FORMAT, XAPIC_DFR_FLAT); ldr = apic_read_reg(APIC_LOGICAL_DEST) & MASK(XAPIC_LDR_SHIFT); ldr |= (BIT(getCurrentCPUIndex()) << XAPIC_LDR_SHIFT); apic_write_reg(APIC_LOGICAL_DEST, ldr); } #endif /* CONFIG_USE_LOGICAL_IDS */ BOOT_CODE bool_t apic_enable(void) { apic_base_msr_t apic_base_msr; apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR); if (!apic_base_msr_get_enabled(apic_base_msr)) { printf("APIC: Enabled bit not set\n"); return false; } if (x2apic_is_enabled()) { printf("x2APIC enabled in BIOS but kernel does not support that\n"); return false; } #ifdef CONFIG_USE_LOGICAL_IDS init_xapic_ldr(); #endif /* CONFIG_USE_LOGICAL_IDS */ return true; } bool_t apic_is_interrupt_pending(void) { word_t i; /* read 256-bit register: each 32-bit word is 16 byte aligned */ assert(int_irq_min % 32 == 0); for (i = int_irq_min; i <= int_irq_max; i += 32) { if (apic_read_reg(APIC_IRR_BASE + i / 2) != 0) { return true; } } return false; } BOOT_CODE void apic_send_init_ipi(cpu_id_t cpu_id) { apic_write_icr( apic_icr2_new( cpu_id /* dest */ ).words[0], apic_icr1_new( 0, /* dest_shorthand */ 1, /* trigger_mode */ 1, /* level */ 0, /* delivery_status */ 0, /* dest_mode */ 5, /* delivery_mode */ 0 /* vector */ ).words[0] ); apic_write_icr( apic_icr2_new( cpu_id /* dest */ ).words[0], apic_icr1_new( 0, /* dest_shorthand */ 1, /* trigger_mode */ 0, /* level */ 0, /* delivery_status */ 0, /* dest_mode */ 5, /* delivery_mode */ 0 /* vector */ ).words[0] ); } BOOT_CODE void apic_send_startup_ipi(cpu_id_t cpu_id, paddr_t startup_addr) { /* check if 4K aligned */ assert(IS_ALIGNED(startup_addr, PAGE_BITS)); /* check if startup_addr < 640K */ assert(startup_addr < 0xa0000); startup_addr >>= PAGE_BITS; apic_write_icr( apic_icr2_new( cpu_id /* dest */ ).words[0], apic_icr1_new( 0, /* dest_shorthand */ 0, /* trigger_mode */ 0, /* level */ 0, /* delivery_status */ 0, /* dest_mode */ 6, /* delivery_mode */ startup_addr /* vector */ ).words[0] ); } void apic_send_ipi_core(irq_t vector, cpu_id_t cpu_id) { apic_icr1_t icr1; /* wait till we can send an IPI */ do { icr1.words[0] = apic_read_reg(APIC_ICR1); } while (apic_icr1_get_delivery_status(icr1)); apic_write_icr( apic_icr2_new( cpu_id /* dest */ ).words[0], apic_icr1_new( 0, /* dest_shorthand */ 0, /* trigger_mode */ 0, /* level */ 0, /* delivery_status */ 0, /* dest_mode */ 0, /* delivery_mode */ vector /* vector */ ).words[0] ); } void apic_send_ipi_cluster(irq_t vector, word_t mda) { apic_icr1_t icr1; /* wait till we can send an IPI */ do { icr1.words[0] = apic_read_reg(APIC_ICR1); } while (apic_icr1_get_delivery_status(icr1)); apic_write_icr( apic_icr2_new( mda /* message destination address */ ).words[0], apic_icr1_new( 0, /* dest_shorthand */ 0, /* trigger_mode */ 0, /* level */ 0, /* delivery_status */ 1, /* dest_mode */ 0, /* delivery_mode */ vector /* vector */ ).words[0] ); } #endif /* CONFIG_XAPIC */