diff --git a/doc/acrn.doxyfile b/doc/acrn.doxyfile index fddfed5b7b..42cf94ae75 100644 --- a/doc/acrn.doxyfile +++ b/doc/acrn.doxyfile @@ -806,9 +806,7 @@ INPUT = custom-doxygen/mainpage.md \ ../hypervisor/include/dm/vpic.h \ ../hypervisor/include/dm/io_req.h \ ../hypervisor/include/arch/x86/guest/vmx_io.h \ - ../hypervisor/include/arch/x86/guest/assign.h \ ../hypervisor/include/common/hypercall.h \ - ../hypervisor/include/common/ptdev.h \ ../hypervisor/include/public/acrn_common.h \ ../hypervisor/include/public/acrn_hv_defs.h \ ../hypervisor/include/arch/x86/guest/vcpu.h \ diff --git a/doc/developer-guides/asm_coding_guidelines.rst b/doc/developer-guides/asm_coding_guidelines.rst index a5fe4a94cc..ed51ed9db3 100644 --- a/doc/developer-guides/asm_coding_guidelines.rst +++ b/doc/developer-guides/asm_coding_guidelines.rst @@ -147,7 +147,7 @@ assembler. Compliant example:: #include - #include + #include .macro asm_showcase_mov movl $0x1, %eax @@ -163,7 +163,7 @@ Compliant example:: .end - #include + #include .macro asm_showcase_mov movl $0x1, %eax diff --git a/doc/developer-guides/hld/hv-startup.rst b/doc/developer-guides/hld/hv-startup.rst index 808dc112f2..0cf8a3f80c 100644 --- a/doc/developer-guides/hld/hv-startup.rst +++ b/doc/developer-guides/hld/hv-startup.rst @@ -53,9 +53,9 @@ description for the flow: physical CPU, and to support CPU sharing. - **Interrupt Init:** Initialize interrupt and exception for native HV - including IDT and ``do_IRQ`` infrastructure; a timer interrupt + including IDT and ``do_irq`` infrastructure; a timer interrupt framework is then built. The native/physical interrupts will go - through this ``do_IRQ`` infrastructure then distribute to special + through this ``do_irq`` infrastructure then distribute to special targets (HV or VMs). - **Start AP:** BSP kicks ``INIT-SIPI-SIPI`` IPI sequence to start other diff --git a/doc/developer-guides/hld/virtio-net.rst b/doc/developer-guides/hld/virtio-net.rst index ecd135bb39..63345d92f1 100644 --- a/doc/developer-guides/hld/virtio-net.rst +++ b/doc/developer-guides/hld/virtio-net.rst @@ -296,7 +296,7 @@ cases.) .. code-block:: c - do_IRQ --> + do_irq --> ... igb_msix_ring --> igbpoll --> diff --git a/hypervisor/Makefile b/hypervisor/Makefile index 85667896c4..a3441fbc6c 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -137,10 +137,7 @@ REL_INCLUDE_PATH += include REL_INCLUDE_PATH += include/lib REL_INCLUDE_PATH += include/lib/crypto REL_INCLUDE_PATH += include/common -REL_INCLUDE_PATH += include/arch/x86 -REL_INCLUDE_PATH += include/arch/x86/boot -REL_INCLUDE_PATH += include/arch/x86/guest -REL_INCLUDE_PATH += include/arch/x86/lib +REL_INCLUDE_PATH += include/arch/ REL_INCLUDE_PATH += include/debug REL_INCLUDE_PATH += include/public REL_INCLUDE_PATH += include/dm @@ -216,7 +213,13 @@ HW_C_SRCS += arch/x86/notify.c HW_C_SRCS += arch/x86/vtd.c HW_C_SRCS += arch/x86/gdt.c HW_C_SRCS += arch/x86/irq.c -HW_C_SRCS += arch/x86/timer.c +HW_C_SRCS += arch/x86/exception.c +HW_C_SRCS += arch/x86/nmi.c +HW_C_SRCS += arch/x86/tsc.c +HW_C_SRCS += arch/x86/tsc_deadline_timer.c +HW_C_SRCS += common/timer.c +HW_C_SRCS += common/udelay.c +HW_C_SRCS += common/cycles.c HW_C_SRCS += arch/x86/vmx.c HW_C_SRCS += arch/x86/cpu_state_tbl.c HW_C_SRCS += arch/x86/pm.c @@ -226,6 +229,7 @@ HW_S_SRCS += arch/x86/sched.S HW_C_SRCS += arch/x86/rdt.c HW_C_SRCS += arch/x86/sgx.c HW_C_SRCS += common/softirq.c +HW_C_SRCS += common/irq.c HW_C_SRCS += common/schedule.c HW_C_SRCS += common/event.c ifeq ($(CONFIG_SCHED_NOOP),y) @@ -298,19 +302,19 @@ VP_DM_C_SRCS += dm/mmio_dev.c VP_DM_C_SRCS += dm/vgpio.c VP_DM_C_SRCS += arch/x86/guest/vlapic.c VP_DM_C_SRCS += arch/x86/guest/pm.c -VP_DM_C_SRCS += arch/x86/guest/assign.c VP_DM_C_SRCS += arch/x86/guest/vmx_io.c VP_DM_C_SRCS += arch/x86/guest/instr_emul.c VP_DM_C_SRCS += arch/x86/guest/splitlock.c VP_DM_C_SRCS += arch/x86/guest/vm_reset.c -VP_DM_C_SRCS += common/ptdev.c +VP_DM_C_SRCS += arch/x86/ptirq.c +VP_DM_C_SRCS += arch/x86/ptintr.c +VP_DM_C_SRCS += common/ptirq.c +VP_DM_C_SRCS += common/ptintr.c # virtual platform trusty VP_TRUSTY_C_SRCS += arch/x86/guest/trusty.c VP_TRUSTY_C_SRCS += common/trusty_hypercall.c -VP_TRUSTY_C_SRCS += arch/x86/seed/seed.c -VP_TRUSTY_C_SRCS += arch/x86/seed/seed_abl.c -VP_TRUSTY_C_SRCS += arch/x86/seed/seed_sbl.c +VP_TRUSTY_C_SRCS += crypto/seed.c # virtual platform hypercall VP_HCALL_C_SRCS += arch/x86/guest/vmcall.c diff --git a/hypervisor/acpi_parser/acpi_ext.c b/hypervisor/acpi_parser/acpi_ext.c index 794859d2c7..8abb70eb0c 100644 --- a/hypervisor/acpi_parser/acpi_ext.c +++ b/hypervisor/acpi_parser/acpi_ext.c @@ -29,13 +29,14 @@ #include #include #include "acpi.h" -#include -#include +#include +#include +#include #include -#include +#include #include #include -#include +#include /* Per ACPI spec: * There are two fundamental types of ACPI tables: diff --git a/hypervisor/acpi_parser/dmar_parse.c b/hypervisor/acpi_parser/dmar_parse.c index b1c36f752f..43c4ad6148 100644 --- a/hypervisor/acpi_parser/dmar_parse.c +++ b/hypervisor/acpi_parser/dmar_parse.c @@ -6,11 +6,11 @@ #include #include -#include -#include -#include +#include +#include +#include +#include #include "pci.h" -#include "vtd.h" #include "acpi.h" static uint32_t dmar_unit_cnt; @@ -105,7 +105,7 @@ static uint32_t get_drhd_dev_scope_cnt(struct acpi_dmar_hardware_unit *drhd) /** * @Application constraint: The dedicated DMAR unit for Intel integrated GPU * shall be available on the physical platform. - */ + */ static int32_t handle_one_drhd(struct acpi_dmar_hardware_unit *acpi_drhd, struct dmar_drhd *drhd) { struct dmar_dev_scope *dev_scope; @@ -134,7 +134,7 @@ static int32_t handle_one_drhd(struct acpi_dmar_hardware_unit *acpi_drhd, struct consumed = handle_dmar_devscope(dev_scope, cp, remaining); /* Disable GPU IOMMU due to gvt-d hasn’t been enabled on APL yet. */ - if (is_apl_platform()) { + if ((pcpu_family_id() == 0x6U) && (pcpu_model_id() == 0x5cU)) { if (((drhd->segment << 16U) | (dev_scope->bus << 8U) | dev_scope->devfun) == CONFIG_GPU_SBDF) { diff --git a/hypervisor/arch/x86/configs/pci_dev.c b/hypervisor/arch/x86/configs/pci_dev.c index b341c6f039..f0b4fe61ae 100644 --- a/hypervisor/arch/x86/configs/pci_dev.c +++ b/hypervisor/arch/x86/configs/pci_dev.c @@ -4,9 +4,9 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include #include -#include +#include #include /* diff --git a/hypervisor/arch/x86/configs/vacpi.c b/hypervisor/arch/x86/configs/vacpi.c index 9cda53b01c..5dfa7defbf 100644 --- a/hypervisor/arch/x86/configs/vacpi.c +++ b/hypervisor/arch/x86/configs/vacpi.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include #include /** diff --git a/hypervisor/arch/x86/configs/vm_config.c b/hypervisor/arch/x86/configs/vm_config.c index 2fd7fef767..89027e1699 100644 --- a/hypervisor/arch/x86/configs/vm_config.c +++ b/hypervisor/arch/x86/configs/vm_config.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include /* * @pre vm_id < CONFIG_MAX_VM_NUM diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index ab0d27a765..1af98170cd 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -5,30 +5,22 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define CPU_UP_TIMEOUT 100U /* millisecond */ #define CPU_DOWN_TIMEOUT 100U /* millisecond */ @@ -41,35 +33,9 @@ static uint64_t startup_paddr = 0UL; /* physical cpu active bitmap, support up to 64 cpus */ static volatile uint64_t pcpu_active_bitmap = 0UL; -static void init_pcpu_xsave(void); static void set_current_pcpu_id(uint16_t pcpu_id); -static void print_hv_banner(void); -static uint16_t get_pcpu_id_from_lapic_id(uint32_t lapic_id); -static uint64_t start_tsc __attribute__((__section__(".bss_noinit"))); -/** - * @pre phys_cpu_num <= MAX_PCPU_NUM - */ -static bool init_percpu_lapic_id(void) -{ - uint16_t i; - uint32_t lapic_id_array[MAX_PCPU_NUM]; - bool success = false; - - /* Save all lapic_id detected via parse_mdt in lapic_id_array */ - phys_cpu_num = parse_madt(lapic_id_array); - - if ((phys_cpu_num != 0U) && (phys_cpu_num <= MAX_PCPU_NUM)) { - for (i = 0U; i < phys_cpu_num; i++) { - per_cpu(lapic_id, i) = lapic_id_array[i]; - } - success = true; - } - - return success; -} - -static void pcpu_set_current_state(uint16_t pcpu_id, enum pcpu_boot_state state) +void pcpu_set_current_state(uint16_t pcpu_id, enum pcpu_boot_state state) { /* Check if state is initializing */ if (state == PCPU_STATE_INITIALIZING) { @@ -82,6 +48,14 @@ static void pcpu_set_current_state(uint16_t pcpu_id, enum pcpu_boot_state state) per_cpu(boot_state, pcpu_id) = state; } +/** + * @pre num <= MAX_PCPU_NUM + */ +void set_pcpu_nums(uint16_t num) +{ + phys_cpu_num = num; +} + /* * @post return <= MAX_PCPU_NUM */ @@ -90,228 +64,30 @@ uint16_t get_pcpu_nums(void) return phys_cpu_num; } -bool is_pcpu_active(uint16_t pcpu_id) -{ - return bitmap_test(pcpu_id, &pcpu_active_bitmap); -} - -uint64_t get_active_pcpu_bitmap(void) -{ - return pcpu_active_bitmap; -} - -static void enable_ac_for_splitlock(void) -{ -#ifndef CONFIG_ENFORCE_TURNOFF_AC - uint64_t test_ctl; - - if (has_core_cap(1U << 5U)) { - test_ctl = msr_read(MSR_TEST_CTL); - test_ctl |= (1U << 29U); - msr_write(MSR_TEST_CTL, test_ctl); - } -#endif /*CONFIG_ENFORCE_TURNOFF_AC*/ -} - -void init_pcpu_pre(bool is_bsp) +void set_active_pcpu_bitmap(uint16_t pcpu_id) { - uint16_t pcpu_id; - int32_t ret; - - if (is_bsp) { - pcpu_id = BSP_CPU_ID; - start_tsc = rdtsc(); - - /* Get CPU capabilities thru CPUID, including the physical address bit - * limit which is required for initializing paging. - */ - init_pcpu_capabilities(); - - if (detect_hardware_support() != 0) { - panic("hardware not support!"); - } - - init_pcpu_model_name(); - - load_pcpu_state_data(); - - /* Initialize the hypervisor paging */ - init_e820(); - init_paging(); - - /* - * Need update uart_base_address here for vaddr2paddr mapping may changed - * WARNNING: DO NOT CALL PRINTF BETWEEN ENABLE PAGING IN init_paging AND HERE! - */ - uart16550_init(false); - - early_init_lapic(); - -#ifdef CONFIG_ACPI_PARSE_ENABLED - ret = acpi_fixup(); - if (ret != 0) { - panic("failed to parse/fix up ACPI table!"); - } -#endif - - if (!init_percpu_lapic_id()) { - panic("failed to init_percpu_lapic_id!"); - } - - ret = init_ioapic_id_info(); - if (ret != 0) { - panic("System IOAPIC info is incorrect!"); - } - -#ifdef CONFIG_RDT_ENABLED - init_rdt_info(); -#endif - - /* NOTE: this must call after MMCONFIG is parsed in acpi_fixup() and before APs are INIT. - * We only support platform with MMIO based CFG space access. - * IO port access only support in debug version. - */ - pci_switch_to_mmio_cfg_ops(); - } else { - - /* Switch this CPU to use the same page tables set-up by the - * primary/boot CPU - */ - enable_paging(); - - early_init_lapic(); - - pcpu_id = get_pcpu_id_from_lapic_id(get_cur_lapic_id()); - if (pcpu_id >= MAX_PCPU_NUM) { - panic("Invalid pCPU ID!"); - } - } - bitmap_set_lock(pcpu_id, &pcpu_active_bitmap); - /* Set state for this CPU to initializing */ - pcpu_set_current_state(pcpu_id, PCPU_STATE_INITIALIZING); } -void init_pcpu_post(uint16_t pcpu_id) +bool is_pcpu_active(uint16_t pcpu_id) { -#ifdef STACK_PROTECTOR - set_fs_base(); -#endif - load_gdtr_and_tr(); - - enable_ac_for_splitlock(); - - init_pcpu_xsave(); - - if (pcpu_id == BSP_CPU_ID) { - /* Print Hypervisor Banner */ - print_hv_banner(); - - /* Calibrate TSC Frequency */ - calibrate_tsc(); - - pr_acrnlog("HV version %s-%s-%s %s (daily tag:%s) %s@%s build by %s%s, start time %luus", - HV_FULL_VERSION, - HV_BUILD_TIME, HV_BUILD_VERSION, HV_BUILD_TYPE, - HV_DAILY_TAG, HV_BUILD_SCENARIO, HV_BUILD_BOARD, - HV_BUILD_USER, HV_CONFIG_TOOL, ticks_to_us(start_tsc)); - - pr_acrnlog("API version %u.%u", HV_API_MAJOR_VERSION, HV_API_MINOR_VERSION); - - pr_acrnlog("Detect processor: %s", (get_pcpu_info())->model_name); - - pr_dbg("Core %hu is up", BSP_CPU_ID); - - /* Warn for security feature not ready */ - if (!check_cpu_security_cap()) { - pr_fatal("SECURITY WARNING!!!!!!"); - pr_fatal("Please apply the latest CPU uCode patch!"); - } - - /* Initialize interrupts */ - init_interrupt(BSP_CPU_ID); - - timer_init(); - setup_notification(); - setup_pi_notification(); - - if (init_iommu() != 0) { - panic("failed to initialize iommu!"); - } - -#ifdef CONFIG_IVSHMEM_ENABLED - init_ivshmem_shared_memory(); -#endif - init_pci_pdev_list(); /* init_iommu must come before this */ - ptdev_init(); - - if (init_sgx() != 0) { - panic("failed to initialize sgx!"); - } - - /* - * Reserve memory from platform E820 for EPT 4K pages for all VMs - */ -#ifdef CONFIG_LAST_LEVEL_EPT_AT_BOOT - reserve_buffer_for_ept_pages(); -#endif - /* Start all secondary cores */ - startup_paddr = prepare_trampoline(); - if (!start_pcpus(AP_MASK)) { - panic("Failed to start all secondary cores!"); - } - - ASSERT(get_pcpu_id() == BSP_CPU_ID, ""); - - init_software_sram(true); - } else { - pr_dbg("Core %hu is up", pcpu_id); - - pr_warn("Skipping VM configuration check which should be done before building HV binary."); - - init_software_sram(false); - - /* Initialize secondary processor interrupts. */ - init_interrupt(pcpu_id); - - timer_init(); - ptdev_init(); - - /* Wait for boot processor to signal all secondary cores to continue */ - wait_sync_change(&pcpu_sync, 0UL); - } - - init_sched(pcpu_id); - -#ifdef CONFIG_RDT_ENABLED - setup_clos(pcpu_id); -#endif - - enable_smep(); - - enable_smap(); + return bitmap_test(pcpu_id, &pcpu_active_bitmap); } -static uint16_t get_pcpu_id_from_lapic_id(uint32_t lapic_id) +uint64_t get_active_pcpu_bitmap(void) { - uint16_t i; - uint16_t pcpu_id = INVALID_CPU_ID; - - for (i = 0U; i < phys_cpu_num; i++) { - if (per_cpu(lapic_id, i) == lapic_id) { - pcpu_id = i; - break; - } - } - - return pcpu_id; + return pcpu_active_bitmap; } static void start_pcpu(uint16_t pcpu_id) { uint32_t timeout; + if (startup_paddr == 0UL) { + startup_paddr = prepare_trampoline(); + } + /* Update the stack for pcpu */ stac(); write_trampoline_stack_sym(pcpu_id); @@ -375,6 +151,11 @@ bool start_pcpus(uint64_t mask) return ((pcpu_active_bitmap & mask) == mask); } +void wait_all_pcpus_run(void) +{ + wait_sync_change(&pcpu_sync, 0UL); +} + void make_pcpu_offline(uint16_t pcpu_id) { bitmap_set_lock(NEED_OFFLINE, &per_cpu(pcpu_flag, pcpu_id)); @@ -463,14 +244,6 @@ static void set_current_pcpu_id(uint16_t pcpu_id) msr_write(MSR_IA32_TSC_AUX, (uint64_t) pcpu_id); } -static void print_hv_banner(void) -{ - const char *boot_msg = "ACRN Hypervisor\n\r"; - - /* Print the boot message */ - printf(boot_msg); -} - static inline void asm_monitor(volatile const uint64_t *addr, uint64_t ecx, uint64_t edx) { @@ -501,49 +274,6 @@ void wait_sync_change(volatile const uint64_t *sync, uint64_t wake_sync) } } -static void init_pcpu_xsave(void) -{ - uint64_t val64; - struct cpuinfo_x86 *cpu_info; - uint64_t xcr0, xss; - uint32_t eax, ecx, unused, xsave_area_size; - - CPU_CR_READ(cr4, &val64); - val64 |= CR4_OSXSAVE; - CPU_CR_WRITE(cr4, val64); - - if (get_pcpu_id() == BSP_CPU_ID) { - cpuid_subleaf(CPUID_FEATURES, 0x0U, &unused, &unused, &ecx, &unused); - - /* if set, update it */ - if ((ecx & CPUID_ECX_OSXSAVE) != 0U) { - cpu_info = get_pcpu_info(); - cpu_info->cpuid_leaves[FEAT_1_ECX] |= CPUID_ECX_OSXSAVE; - - /* set xcr0 and xss with the componets bitmap get from cpuid */ - xcr0 = ((uint64_t)cpu_info->cpuid_leaves[FEAT_D_0_EDX] << 32U) - + cpu_info->cpuid_leaves[FEAT_D_0_EAX]; - xss = ((uint64_t)cpu_info->cpuid_leaves[FEAT_D_1_EDX] << 32U) - + cpu_info->cpuid_leaves[FEAT_D_1_ECX]; - write_xcr(0, xcr0); - msr_write(MSR_IA32_XSS, xss); - - /* get xsave area size, containing all the state components - * corresponding to bits currently set in XCR0 | IA32_XSS */ - cpuid_subleaf(CPUID_XSAVE_FEATURES, 1U, - &eax, - &xsave_area_size, - &ecx, - &unused); - if (xsave_area_size > XSAVE_STATE_AREA_SIZE) { - panic("XSAVE area (%d bytes) exceeds the pre-allocated 4K region\n", - xsave_area_size); - } - } - } -} - - static void smpcall_write_msr_func(void *data) { struct msr_data_struct *msr = (struct msr_data_struct *)data; diff --git a/hypervisor/arch/x86/cpu_caps.c b/hypervisor/arch/x86/cpu_caps.c index 238955ecee..53864c0e25 100644 --- a/hypervisor/arch/x86/cpu_caps.c +++ b/hypervisor/arch/x86/cpu_caps.c @@ -5,17 +5,16 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include /* TODO: add more capability per requirement */ /* APICv features */ @@ -40,8 +39,35 @@ static struct cpu_capability { uint32_t core_caps; /* value of MSR_IA32_CORE_CAPABLITIES */ } cpu_caps; +struct cpuinfo_x86 { + /* SDM 2-2 Vol.4 Table 2-1 uses DisplayFamily_DisplayModel to + * distinguish Processor Families/Processor Number Series. + */ + uint8_t displayfamily, displaymodel; + uint8_t virt_bits; + uint8_t phys_bits; + uint32_t cpuid_level; + uint32_t extended_cpuid_level; + uint32_t cpuid_leaves[FEATURE_WORDS]; + char model_name[64]; +}; + static struct cpuinfo_x86 boot_cpu_data; +bool pcpu_set_cap(uint32_t bit) +{ + uint32_t feat_idx = bit >> 5U; + uint32_t feat_bit = bit & 0x1fU; + bool ret = false; + + if (feat_idx < FEATURE_WORDS) { + boot_cpu_data.cpuid_leaves[feat_idx] |= (1U << feat_bit); + ret = true; + } + + return ret; +} + bool pcpu_has_cap(uint32_t bit) { uint32_t feat_idx = bit >> 5U; @@ -62,11 +88,11 @@ bool has_monitor_cap(void) bool ret = false; if (pcpu_has_cap(X86_FEATURE_MONITOR)) { - /* don't use monitor for CPU (family: 0x6 model: 0x5c) + /* don't use monitor for APL CPU (family: 0x6 model: 0x5c) * in hypervisor, but still expose it to the guests and * let them handle it correctly */ - if (!is_apl_platform()) { + if (!((pcpu_family_id() == 0x6U) && (pcpu_model_id() == 0x5cU))) { ret = true; } } @@ -74,6 +100,36 @@ bool has_monitor_cap(void) return ret; } +uint8_t pcpu_physaddr_bits(void) +{ + return boot_cpu_data.phys_bits; +} + +uint8_t pcpu_virtaddr_bits(void) +{ + return boot_cpu_data.virt_bits; +} + +uint32_t pcpu_cpuid_level(void) +{ + return boot_cpu_data.cpuid_level; +} + +uint8_t pcpu_family_id(void) +{ + return boot_cpu_data.displayfamily; +} + +uint8_t pcpu_model_id(void) +{ + return boot_cpu_data.displaymodel; +} + +char *pcpu_model_name(void) +{ + return boot_cpu_data.model_name; +} + static inline bool is_fast_string_erms_supported_and_enabled(void) { bool ret = false; @@ -103,17 +159,6 @@ static bool is_ctrl_setting_allowed(uint64_t msr_val, uint32_t ctrl) return ((((uint32_t)(msr_val >> 32UL)) & ctrl) == ctrl); } -bool is_apl_platform(void) -{ - bool ret = false; - - if ((boot_cpu_data.displayfamily == 0x6U) && (boot_cpu_data.displaymodel == 0x5cU)) { - ret = true; - } - - return ret; -} - bool has_core_cap(uint32_t bit_mask) { return ((cpu_caps.core_caps & bit_mask) != 0U); @@ -243,9 +288,25 @@ static void detect_pcpu_cap(void) detect_core_caps(); } -static uint64_t get_address_mask(uint8_t limit) +static void init_pcpu_model_name(void) { - return ((1UL << limit) - 1UL) & PAGE_MASK; + cpuid_subleaf(CPUID_EXTEND_FUNCTION_2, 0x0U, + (uint32_t *)(boot_cpu_data.model_name), + (uint32_t *)(&boot_cpu_data.model_name[4]), + (uint32_t *)(&boot_cpu_data.model_name[8]), + (uint32_t *)(&boot_cpu_data.model_name[12])); + cpuid_subleaf(CPUID_EXTEND_FUNCTION_3, 0x0U, + (uint32_t *)(&boot_cpu_data.model_name[16]), + (uint32_t *)(&boot_cpu_data.model_name[20]), + (uint32_t *)(&boot_cpu_data.model_name[24]), + (uint32_t *)(&boot_cpu_data.model_name[28])); + cpuid_subleaf(CPUID_EXTEND_FUNCTION_4, 0x0U, + (uint32_t *)(&boot_cpu_data.model_name[32]), + (uint32_t *)(&boot_cpu_data.model_name[36]), + (uint32_t *)(&boot_cpu_data.model_name[40]), + (uint32_t *)(&boot_cpu_data.model_name[44])); + + boot_cpu_data.model_name[48] = '\0'; } void init_pcpu_capabilities(void) @@ -307,11 +368,10 @@ void init_pcpu_capabilities(void) */ boot_cpu_data.virt_bits = (uint8_t)((eax >> 8U) & 0xffU); boot_cpu_data.phys_bits = (uint8_t)(eax & 0xffU); - boot_cpu_data.physical_address_mask = - get_address_mask(boot_cpu_data.phys_bits); } detect_pcpu_cap(); + init_pcpu_model_name(); } static bool is_ept_supported(void) @@ -339,27 +399,6 @@ bool pcpu_has_vmx_vpid_cap(uint32_t bit_mask) return ((cpu_caps.vmx_vpid & bit_mask) != 0U); } -void init_pcpu_model_name(void) -{ - cpuid_subleaf(CPUID_EXTEND_FUNCTION_2, 0x0U, - (uint32_t *)(boot_cpu_data.model_name), - (uint32_t *)(&boot_cpu_data.model_name[4]), - (uint32_t *)(&boot_cpu_data.model_name[8]), - (uint32_t *)(&boot_cpu_data.model_name[12])); - cpuid_subleaf(CPUID_EXTEND_FUNCTION_3, 0x0U, - (uint32_t *)(&boot_cpu_data.model_name[16]), - (uint32_t *)(&boot_cpu_data.model_name[20]), - (uint32_t *)(&boot_cpu_data.model_name[24]), - (uint32_t *)(&boot_cpu_data.model_name[28])); - cpuid_subleaf(CPUID_EXTEND_FUNCTION_4, 0x0U, - (uint32_t *)(&boot_cpu_data.model_name[32]), - (uint32_t *)(&boot_cpu_data.model_name[36]), - (uint32_t *)(&boot_cpu_data.model_name[40]), - (uint32_t *)(&boot_cpu_data.model_name[44])); - - boot_cpu_data.model_name[48] = '\0'; -} - static inline bool is_vmx_disabled(void) { uint64_t msr_val; @@ -497,8 +536,3 @@ int32_t detect_hardware_support(void) return ret; } - -struct cpuinfo_x86 *get_pcpu_info(void) -{ - return &boot_cpu_data; -} diff --git a/hypervisor/arch/x86/cpu_state_tbl.c b/hypervisor/arch/x86/cpu_state_tbl.c index a8eef09ae0..b57397fb65 100644 --- a/hypervisor/arch/x86/cpu_state_tbl.c +++ b/hypervisor/arch/x86/cpu_state_tbl.c @@ -7,9 +7,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include /* The table includes cpu px info of Intel A3960 SoC */ static const struct cpu_px_data px_a3960[17] = { @@ -180,18 +180,17 @@ void load_pcpu_state_data(void) { int32_t tbl_idx; const struct cpu_state_info *state_info = NULL; - struct cpuinfo_x86 *cpu_info = get_pcpu_info(); (void)memset(&cpu_pm_state_info, 0U, sizeof(struct cpu_state_info)); - tbl_idx = get_state_tbl_idx(cpu_info->model_name); + tbl_idx = get_state_tbl_idx(pcpu_model_name()); if (tbl_idx >= 0) { /* The cpu state table is found at global cpu_state_tbl[]. */ state_info = &(cpu_state_tbl + tbl_idx)->state_info; } else { /* check whether board.c has a valid cpu state table which generated by offline tool */ - if (strcmp((board_cpu_state_tbl.model_name), cpu_info->model_name) == 0) { + if (strcmp((board_cpu_state_tbl.model_name), pcpu_model_name()) == 0) { state_info = &board_cpu_state_tbl.state_info; } } diff --git a/hypervisor/arch/x86/e820.c b/hypervisor/arch/x86/e820.c index 23899a2328..548bbd0107 100644 --- a/hypervisor/arch/x86/e820.c +++ b/hypervisor/arch/x86/e820.c @@ -6,12 +6,12 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include -#include +#include /* * e820.c contains the related e820 operations; like HV to get memory info for its MMU setup; diff --git a/hypervisor/arch/x86/exception.c b/hypervisor/arch/x86/exception.c new file mode 100644 index 0000000000..18d2a0e9b7 --- /dev/null +++ b/hypervisor/arch/x86/exception.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +void dispatch_exception(struct intr_excp_ctx *ctx) +{ + uint16_t pcpu_id = get_pcpu_id(); + + /* Dump exception context */ + dump_exception(ctx, pcpu_id); + + /* Halt the CPU */ + cpu_dead(); + +} diff --git a/hypervisor/arch/x86/gdt.c b/hypervisor/arch/x86/gdt.c index 25654efe52..8ac23c7d5e 100644 --- a/hypervisor/arch/x86/gdt.c +++ b/hypervisor/arch/x86/gdt.c @@ -5,8 +5,8 @@ */ #include -#include -#include +#include +#include static void set_tss_desc(struct tss_64_descriptor *desc, uint64_t tss, size_t tss_limit, uint32_t type) diff --git a/hypervisor/arch/x86/guest/assign.c b/hypervisor/arch/x86/guest/assign.c deleted file mode 100644 index f19869c90d..0000000000 --- a/hypervisor/arch/x86/guest/assign.c +++ /dev/null @@ -1,827 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Check if the IRQ is single-destination and return the destination vCPU if so. - * - * VT-d PI (posted mode) cannot support multicast/broadcast IRQs. - * If returns NULL, this means it is multicast/broadcast IRQ and - * we can only handle it in remapped mode. - * If returns non-NULL, the destination vCPU is returned, which means it is - * single-destination IRQ and we can handle it in posted mode. - * - * @pre (vm != NULL) && (info != NULL) - */ -static struct acrn_vcpu *is_single_destination(struct acrn_vm *vm, const struct msi_info *info) -{ - uint64_t vdmask; - uint16_t vid; - struct acrn_vcpu *vcpu = NULL; - - vlapic_calc_dest(vm, &vdmask, false, (uint32_t)(info->addr.bits.dest_field), - (bool)(info->addr.bits.dest_mode == MSI_ADDR_DESTMODE_PHYS), - (bool)(info->data.bits.delivery_mode == MSI_DATA_DELMODE_LOPRI)); - - vid = ffs64(vdmask); - - /* Can only post fixed and Lowpri IRQs */ - if ((info->data.bits.delivery_mode == MSI_DATA_DELMODE_FIXED) - || (info->data.bits.delivery_mode == MSI_DATA_DELMODE_LOPRI)) { - /* Can only post single-destination IRQs */ - if (vdmask == (1UL << vid)) { - vcpu = vcpu_from_vid(vm, vid); - } - } - - return vcpu; -} - -static uint32_t calculate_logical_dest_mask(uint64_t pdmask) -{ - uint32_t dest_mask = 0UL; - uint64_t pcpu_mask = pdmask; - uint16_t pcpu_id; - - pcpu_id = ffs64(pcpu_mask); - while (pcpu_id < MAX_PCPU_NUM) { - bitmap_clear_nolock(pcpu_id, &pcpu_mask); - dest_mask |= per_cpu(lapic_ldr, pcpu_id); - pcpu_id = ffs64(pcpu_mask); - } - return dest_mask; -} - -/** - * @pre entry != NULL - */ -static void ptirq_free_irte(const struct ptirq_remapping_info *entry) -{ - struct intr_source intr_src; - - if (entry->irte_idx < CONFIG_MAX_IR_ENTRIES) { - if (entry->intr_type == PTDEV_INTR_MSI) { - intr_src.is_msi = true; - intr_src.src.msi.value = entry->phys_sid.msi_id.bdf; - } else { - intr_src.is_msi = false; - intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(entry->allocated_pirq); - } - dmar_free_irte(&intr_src, entry->irte_idx); - } -} - -/* - * pid_paddr = 0: invalid address, indicate that remapped mode shall be used - * - * pid_paddr != 0: physical address of posted interrupt descriptor, indicate - * that posted mode shall be used - */ -static void ptirq_build_physical_msi(struct acrn_vm *vm, - struct ptirq_remapping_info *entry, uint32_t vector, uint64_t pid_paddr, uint16_t irte_idx) -{ - uint64_t vdmask, pdmask; - uint32_t dest, delmode, dest_mask; - bool phys; - union dmar_ir_entry irte; - union irte_index ir_index; - int32_t ret; - struct intr_source intr_src; - - /* get physical destination cpu mask */ - dest = entry->vmsi.addr.bits.dest_field; - phys = (entry->vmsi.addr.bits.dest_mode == MSI_ADDR_DESTMODE_PHYS); - - vlapic_calc_dest(vm, &vdmask, false, dest, phys, false); - pdmask = vcpumask2pcpumask(vm, vdmask); - - /* get physical delivery mode */ - delmode = entry->vmsi.data.bits.delivery_mode; - if ((delmode != MSI_DATA_DELMODE_FIXED) && (delmode != MSI_DATA_DELMODE_LOPRI)) { - delmode = MSI_DATA_DELMODE_LOPRI; - } - - dest_mask = calculate_logical_dest_mask(pdmask); - - /* Using phys_irq as index in the corresponding IOMMU */ - irte.value.lo_64 = 0UL; - irte.value.hi_64 = 0UL; - irte.bits.remap.vector = vector; - irte.bits.remap.delivery_mode = delmode; - irte.bits.remap.dest_mode = MSI_ADDR_DESTMODE_LOGICAL; - irte.bits.remap.rh = MSI_ADDR_RH; - irte.bits.remap.dest = dest_mask; - - intr_src.is_msi = true; - intr_src.pid_paddr = pid_paddr; - intr_src.src.msi.value = entry->phys_sid.msi_id.bdf; - if (entry->irte_idx == INVALID_IRTE_ID) { - entry->irte_idx = irte_idx; - } - ret = dmar_assign_irte(&intr_src, &irte, entry->irte_idx, &ir_index.index); - - if (ret == 0) { - entry->pmsi.data.full = 0U; - entry->pmsi.addr.full = 0UL; - entry->irte_idx = ir_index.index; - if (ir_index.index != INVALID_IRTE_ID) { - /* - * Update the MSI interrupt source to point to the IRTE - * SHV is set to 0 as ACRN disables MMC (Multi-Message Capable - * for MSI devices. - */ - entry->pmsi.addr.ir_bits.intr_index_high = ir_index.bits.index_high; - entry->pmsi.addr.ir_bits.shv = 0U; - entry->pmsi.addr.ir_bits.intr_format = 0x1U; - entry->pmsi.addr.ir_bits.intr_index_low = ir_index.bits.index_low; - entry->pmsi.addr.ir_bits.constant = 0xFEEU; - } - } else { - /* In case there is no corresponding IOMMU, for example, if the - * IOMMU is ignored, pass the MSI info in Compatibility Format - */ - entry->pmsi.data = entry->vmsi.data; - entry->pmsi.data.bits.delivery_mode = delmode; - entry->pmsi.data.bits.vector = vector; - - entry->pmsi.addr = entry->vmsi.addr; - entry->pmsi.addr.bits.dest_field = dest_mask; - entry->pmsi.addr.bits.rh = MSI_ADDR_RH; - entry->pmsi.addr.bits.dest_mode = MSI_ADDR_DESTMODE_LOGICAL; - } - dev_dbg(DBG_LEVEL_IRQ, "MSI %s addr:data = 0x%lx:%x(V) -> 0x%lx:%x(P)", - (entry->pmsi.addr.ir_bits.intr_format != 0U) ? " Remappable Format" : "Compatibility Format", - entry->vmsi.addr.full, entry->vmsi.data.full, - entry->pmsi.addr.full, entry->pmsi.data.full); -} - -static union ioapic_rte -ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry) -{ - union ioapic_rte rte; - uint32_t phys_irq = entry->allocated_pirq; - union source_id *virt_sid = &entry->virt_sid; - union irte_index ir_index; - union dmar_ir_entry irte; - struct intr_source intr_src; - int32_t ret; - - if (virt_sid->intx_id.ctlr == INTX_CTLR_IOAPIC) { - uint64_t vdmask, pdmask; - uint32_t dest, delmode, dest_mask, vector; - union ioapic_rte virt_rte; - bool phys; - - vioapic_get_rte(vm, virt_sid->intx_id.gsi, &virt_rte); - rte = virt_rte; - - /* init polarity & pin state */ - if (rte.bits.intr_polarity == IOAPIC_RTE_INTPOL_ALO) { - if (entry->polarity == 0U) { - vioapic_set_irqline_nolock(vm, virt_sid->intx_id.gsi, GSI_SET_HIGH); - } - entry->polarity = 1U; - } else { - if (entry->polarity == 1U) { - vioapic_set_irqline_nolock(vm, virt_sid->intx_id.gsi, GSI_SET_LOW); - } - entry->polarity = 0U; - } - - /* physical destination cpu mask */ - phys = (virt_rte.bits.dest_mode == IOAPIC_RTE_DESTMODE_PHY); - dest = (uint32_t)virt_rte.bits.dest_field; - vlapic_calc_dest(vm, &vdmask, false, dest, phys, false); - pdmask = vcpumask2pcpumask(vm, vdmask); - - /* physical delivery mode */ - delmode = virt_rte.bits.delivery_mode; - if ((delmode != IOAPIC_RTE_DELMODE_FIXED) && - (delmode != IOAPIC_RTE_DELMODE_LOPRI)) { - delmode = IOAPIC_RTE_DELMODE_LOPRI; - } - - /* update physical delivery mode, dest mode(logical) & vector */ - vector = irq_to_vector(phys_irq); - dest_mask = calculate_logical_dest_mask(pdmask); - - irte.value.lo_64 = 0UL; - irte.value.hi_64 = 0UL; - irte.bits.remap.vector = vector; - irte.bits.remap.delivery_mode = delmode; - irte.bits.remap.dest_mode = IOAPIC_RTE_DESTMODE_LOGICAL; - irte.bits.remap.dest = dest_mask; - irte.bits.remap.trigger_mode = rte.bits.trigger_mode; - - intr_src.is_msi = false; - intr_src.pid_paddr = 0UL; - intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq); - ret = dmar_assign_irte(&intr_src, &irte, entry->irte_idx, &ir_index.index); - - if (ret == 0) { - entry->irte_idx = ir_index.index; - if (ir_index.index != INVALID_IRTE_ID) { - rte.ir_bits.vector = vector; - rte.ir_bits.constant = 0U; - rte.ir_bits.intr_index_high = ir_index.bits.index_high; - rte.ir_bits.intr_format = 1U; - rte.ir_bits.intr_index_low = ir_index.bits.index_low; - } else { - rte.bits.intr_mask = 1; - } - } else { - rte.bits.dest_mode = IOAPIC_RTE_DESTMODE_LOGICAL; - rte.bits.delivery_mode = delmode; - rte.bits.vector = vector; - rte.bits.dest_field = dest_mask; - } - - dev_dbg(DBG_LEVEL_IRQ, "IOAPIC RTE %s = 0x%x:%x(V) -> 0x%x:%x(P)", - (rte.ir_bits.intr_format != 0U) ? "Remappable Format" : "Compatibility Format", - virt_rte.u.hi_32, virt_rte.u.lo_32, - rte.u.hi_32, rte.u.lo_32); - } else { - enum vpic_trigger trigger; - union ioapic_rte phys_rte; - - /* just update trigger mode */ - ioapic_get_rte(phys_irq, &phys_rte); - rte = phys_rte; - rte.bits.trigger_mode = IOAPIC_RTE_TRGRMODE_EDGE; - vpic_get_irqline_trigger_mode(vm_pic(vm), (uint32_t)virt_sid->intx_id.gsi, &trigger); - if (trigger == LEVEL_TRIGGER) { - rte.bits.trigger_mode = IOAPIC_RTE_TRGRMODE_LEVEL; - } - - dev_dbg(DBG_LEVEL_IRQ, "IOAPIC RTE %s = 0x%x:%x(P) -> 0x%x:%x(P)", - (rte.ir_bits.intr_format != 0U) ? "Remappable Format" : "Compatibility Format", - phys_rte.u.hi_32, phys_rte.u.lo_32, - rte.u.hi_32, rte.u.lo_32); - } - - return rte; -} - -/* add msix entry for a vm, based on msi id (phys_bdf+msix_index) - * - if the entry not be added by any vm, allocate it - * - if the entry already be added by sos_vm, then change the owner to current vm - * - if the entry already be added by other vm, return NULL - */ -static struct ptirq_remapping_info *add_msix_remapping(struct acrn_vm *vm, - uint16_t virt_bdf, uint16_t phys_bdf, uint32_t entry_nr) -{ - struct ptirq_remapping_info *entry; - DEFINE_MSI_SID(phys_sid, phys_bdf, entry_nr); - DEFINE_MSI_SID(virt_sid, virt_bdf, entry_nr); - - entry = find_ptirq_entry(PTDEV_INTR_MSI, &phys_sid, NULL); - if (entry == NULL) { - entry = ptirq_alloc_entry(vm, PTDEV_INTR_MSI); - if (entry != NULL) { - entry->phys_sid.value = phys_sid.value; - entry->virt_sid.value = virt_sid.value; - entry->release_cb = ptirq_free_irte; - - /* update msi source and active entry */ - if (ptirq_activate_entry(entry, IRQ_INVALID) < 0) { - ptirq_release_entry(entry); - entry = NULL; - } - } - - dev_dbg(DBG_LEVEL_IRQ, "VM%d MSIX add vector mapping vbdf%x:pbdf%x idx=%d", - vm->vm_id, virt_bdf, phys_bdf, entry_nr); - } - - return entry; -} - -/* deactive & remove mapping entry of vbdf:entry_nr for vm */ -static void -remove_msix_remapping(const struct acrn_vm *vm, uint16_t phys_bdf, uint32_t entry_nr) -{ - struct ptirq_remapping_info *entry; - DEFINE_MSI_SID(phys_sid, phys_bdf, entry_nr); - struct intr_source intr_src; - - entry = find_ptirq_entry(PTDEV_INTR_MSI, &phys_sid, NULL); - if ((entry != NULL) && (entry->vm == vm)) { - if (is_entry_active(entry)) { - /*TODO: disable MSIX device when HV can in future */ - ptirq_deactivate_entry(entry); - } - - intr_src.is_msi = true; - intr_src.src.msi.value = entry->phys_sid.msi_id.bdf; - dmar_free_irte(&intr_src, entry->irte_idx); - - dev_dbg(DBG_LEVEL_IRQ, "VM%d MSIX remove vector mapping vbdf-pbdf:0x%x-0x%x idx=%d", - vm->vm_id, entry->virt_sid.msi_id.bdf, phys_bdf, entry_nr); - - ptirq_release_entry(entry); - } - -} - -/* add intx entry for a vm, based on intx id (phys_pin) - * - if the entry not be added by any vm, allocate it - * - if the entry already be added by sos_vm, then change the owner to current vm - * - if the entry already be added by other vm, return NULL - */ -static struct ptirq_remapping_info *add_intx_remapping(struct acrn_vm *vm, uint32_t virt_gsi, - uint32_t phys_gsi, enum intx_ctlr vgsi_ctlr) -{ - struct ptirq_remapping_info *entry = NULL; - DEFINE_INTX_SID(phys_sid, phys_gsi, INTX_CTLR_IOAPIC); - DEFINE_INTX_SID(virt_sid, virt_gsi, vgsi_ctlr); - uint32_t phys_irq = ioapic_gsi_to_irq(phys_gsi); - - entry = find_ptirq_entry(PTDEV_INTR_INTX, &phys_sid, NULL); - if (entry == NULL) { - if (find_ptirq_entry(PTDEV_INTR_INTX, &virt_sid, vm) == NULL) { - entry = ptirq_alloc_entry(vm, PTDEV_INTR_INTX); - if (entry != NULL) { - entry->phys_sid.value = phys_sid.value; - entry->virt_sid.value = virt_sid.value; - entry->release_cb = ptirq_free_irte; - - /* activate entry */ - if (ptirq_activate_entry(entry, phys_irq) < 0) { - ptirq_release_entry(entry); - entry = NULL; - } - } - } else { - pr_err("INTX re-add vpin %d", virt_gsi); - } - } else if (entry->vm != vm) { - if (is_sos_vm(entry->vm)) { - entry->vm = vm; - entry->virt_sid.value = virt_sid.value; - entry->polarity = 0U; - } else { - pr_err("INTX gsi%d already in vm%d with vgsi%d, not able to add into vm%d with vgsi%d", - phys_gsi, entry->vm->vm_id, entry->virt_sid.intx_id.gsi, vm->vm_id, virt_gsi); - entry = NULL; - } - } else { - /* The mapping has already been added to the VM. No action - * required. - */ - } - - - /* - * ptirq entry is either created or transferred from SOS VM to Post-launched VM - */ - - if (entry != NULL) { - dev_dbg(DBG_LEVEL_IRQ, "VM%d INTX add pin mapping vgsi%d:pgsi%d", - entry->vm->vm_id, virt_gsi, phys_gsi); - } - - return entry; -} - -/* deactive & remove mapping entry of vpin for vm */ -static void remove_intx_remapping(const struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_ctlr) -{ - uint32_t phys_irq; - struct ptirq_remapping_info *entry; - struct intr_source intr_src; - DEFINE_INTX_SID(virt_sid, virt_gsi, vgsi_ctlr); - - entry = find_ptirq_entry(PTDEV_INTR_INTX, &virt_sid, vm); - if (entry != NULL) { - if (is_entry_active(entry)) { - phys_irq = entry->allocated_pirq; - /* disable interrupt */ - ioapic_gsi_mask_irq(phys_irq); - - ptirq_deactivate_entry(entry); - intr_src.is_msi = false; - intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq); - - dmar_free_irte(&intr_src, entry->irte_idx); - dev_dbg(DBG_LEVEL_IRQ, - "deactive %s intx entry:pgsi=%d, pirq=%d ", - (vgsi_ctlr == INTX_CTLR_PIC) ? "vPIC" : "vIOAPIC", - entry->phys_sid.intx_id.gsi, phys_irq); - dev_dbg(DBG_LEVEL_IRQ, "from vm%d vgsi=%d\n", - entry->vm->vm_id, virt_gsi); - } - - ptirq_release_entry(entry); - } -} - -static void ptirq_handle_intx(struct acrn_vm *vm, - const struct ptirq_remapping_info *entry) -{ - const union source_id *virt_sid = &entry->virt_sid; - - switch (virt_sid->intx_id.ctlr) { - case INTX_CTLR_IOAPIC: - { - union ioapic_rte rte; - bool trigger_lvl = false; - - /* INTX_CTLR_IOAPIC means we have vioapic enabled */ - vioapic_get_rte(vm, (uint32_t)virt_sid->intx_id.gsi, &rte); - if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) { - trigger_lvl = true; - } - - if (trigger_lvl) { - if (entry->polarity != 0U) { - vioapic_set_irqline_lock(vm, virt_sid->intx_id.gsi, GSI_SET_LOW); - } else { - vioapic_set_irqline_lock(vm, virt_sid->intx_id.gsi, GSI_SET_HIGH); - } - } else { - if (entry->polarity != 0U) { - vioapic_set_irqline_lock(vm, virt_sid->intx_id.gsi, GSI_FALLING_PULSE); - } else { - vioapic_set_irqline_lock(vm, virt_sid->intx_id.gsi, GSI_RAISING_PULSE); - } - } - - dev_dbg(DBG_LEVEL_PTIRQ, - "dev-assign: irq=0x%x assert vr: 0x%x vRTE=0x%lx", - entry->allocated_pirq, - irq_to_vector(entry->allocated_pirq), - rte.full); - break; - } - case INTX_CTLR_PIC: - { - enum vpic_trigger trigger; - - /* INTX_CTLR_PIC means we have vpic enabled */ - vpic_get_irqline_trigger_mode(vm_pic(vm), virt_sid->intx_id.gsi, &trigger); - if (trigger == LEVEL_TRIGGER) { - vpic_set_irqline(vm_pic(vm), virt_sid->intx_id.gsi, GSI_SET_HIGH); - } else { - vpic_set_irqline(vm_pic(vm), virt_sid->intx_id.gsi, GSI_RAISING_PULSE); - } - break; - } - default: - /* - * In this switch statement, virt_sid->intx_id.ctlr shall - * either be INTX_CTLR_IOAPIC or INTX_CTLR_PIC. - * Gracefully return if prior case clauses have not been met. - */ - break; - } -} - -void ptirq_softirq(uint16_t pcpu_id) -{ - while (1) { - struct ptirq_remapping_info *entry = ptirq_dequeue_softirq(pcpu_id); - struct msi_info *vmsi; - - if (entry == NULL) { - break; - } - - vmsi = &entry->vmsi; - - /* skip any inactive entry */ - if (!is_entry_active(entry)) { - /* service next item */ - continue; - } - - /* handle real request */ - if (entry->intr_type == PTDEV_INTR_INTX) { - ptirq_handle_intx(entry->vm, entry); - } else { - if (vmsi != NULL) { - /* TODO: vmsi destmode check required */ - (void)vlapic_inject_msi(entry->vm, vmsi->addr.full, vmsi->data.full); - dev_dbg(DBG_LEVEL_PTIRQ, "dev-assign: irq=0x%x MSI VR: 0x%x-0x%x", - entry->allocated_pirq, vmsi->data.bits.vector, - irq_to_vector(entry->allocated_pirq)); - dev_dbg(DBG_LEVEL_PTIRQ, " vmsi_addr: 0x%lx vmsi_data: 0x%x", - vmsi->addr.full, vmsi->data.full); - } - } - } -} - -void ptirq_intx_ack(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_ctlr) -{ - uint32_t phys_irq; - struct ptirq_remapping_info *entry; - DEFINE_INTX_SID(virt_sid, virt_gsi, vgsi_ctlr); - - entry = find_ptirq_entry(PTDEV_INTR_INTX, &virt_sid, vm); - if (entry != NULL) { - phys_irq = entry->allocated_pirq; - - /* NOTE: only Level trigger will process EOI/ACK and if we got here - * means we have this vioapic or vpic or both enabled - */ - switch (vgsi_ctlr) { - case INTX_CTLR_IOAPIC: - if (entry->polarity != 0U) { - vioapic_set_irqline_lock(vm, virt_gsi, GSI_SET_HIGH); - } else { - vioapic_set_irqline_lock(vm, virt_gsi, GSI_SET_LOW); - } - break; - case INTX_CTLR_PIC: - vpic_set_irqline(vm_pic(vm), virt_gsi, GSI_SET_LOW); - break; - default: - /* - * In this switch statement, vgsi_ctlr shall either be - * INTX_CTLR_IOAPIC or INTX_CTLR_PIC. - * Gracefully return if prior case clauses have not been met. - */ - break; - } - - dev_dbg(DBG_LEVEL_PTIRQ, "dev-assign: irq=0x%x acked vr: 0x%x", - phys_irq, irq_to_vector(phys_irq)); - ioapic_gsi_unmask_irq(phys_irq); - } -} - -/* Main entry for PCI device assignment with MSI and MSI-X - * MSI can up to 8 vectors and MSI-X can up to 1024 Vectors - * We use entry_nr to indicate coming vectors - * entry_nr = 0 means first vector - * user must provide bdf and entry_nr - */ -int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t phys_bdf, - uint16_t entry_nr, struct msi_info *info, uint16_t irte_idx) -{ - struct ptirq_remapping_info *entry; - int32_t ret = -ENODEV; - union pci_bdf vbdf; - - /* - * adds the mapping entries at runtime, if the - * entry already be held by others, return error. - */ - spinlock_obtain(&ptdev_lock); - entry = add_msix_remapping(vm, virt_bdf, phys_bdf, entry_nr); - spinlock_release(&ptdev_lock); - - if (entry != NULL) { - ret = 0; - entry->vmsi = *info; - - /* build physical config MSI, update to info->pmsi_xxx */ - if (is_lapic_pt_configured(vm)) { - enum vm_vlapic_mode vlapic_mode = check_vm_vlapic_mode(vm); - - if (vlapic_mode == VM_VLAPIC_X2APIC) { - /* - * All the vCPUs are in x2APIC mode and LAPIC is Pass-through - * Use guest vector to program the interrupt source - */ - ptirq_build_physical_msi(vm, entry, (uint32_t)info->data.bits.vector, 0UL, irte_idx); - } else if (vlapic_mode == VM_VLAPIC_XAPIC) { - /* - * All the vCPUs are in xAPIC mode and LAPIC is emulated - * Use host vector to program the interrupt source - */ - ptirq_build_physical_msi(vm, entry, irq_to_vector(entry->allocated_pirq), 0UL, irte_idx); - } else if (vlapic_mode == VM_VLAPIC_TRANSITION) { - /* - * vCPUs are in middle of transition, so do not program interrupt source - * TODO: Devices programmed during transistion do not work after transition - * as device is not programmed with interrupt info. Need to implement a - * method to get interrupts working after transition. - */ - ret = -EFAULT; - } else { - /* Do nothing for VM_VLAPIC_DISABLED */ - ret = -EFAULT; - } - } else { - struct acrn_vcpu *vcpu = is_single_destination(vm, info); - - if (is_pi_capable(vm) && (vcpu != NULL)) { - ptirq_build_physical_msi(vm, entry, - (uint32_t)info->data.bits.vector, hva2hpa(get_pi_desc(vcpu)), irte_idx); - } else { - /* Go with remapped mode if we cannot handle it in posted mode */ - ptirq_build_physical_msi(vm, entry, irq_to_vector(entry->allocated_pirq), 0UL, irte_idx); - } - } - - if (ret == 0) { - *info = entry->pmsi; - vbdf.value = virt_bdf; - dev_dbg(DBG_LEVEL_IRQ, "PCI %x:%x.%x MSI VR[%d] 0x%x->0x%x assigned to vm%d", - vbdf.bits.b, vbdf.bits.d, vbdf.bits.f, entry_nr, entry->vmsi.data.bits.vector, - irq_to_vector(entry->allocated_pirq), entry->vm->vm_id); - } - } - - return ret; -} - -static void activate_physical_ioapic(struct acrn_vm *vm, - struct ptirq_remapping_info *entry) -{ - union ioapic_rte rte; - uint32_t phys_irq = entry->allocated_pirq; - uint64_t intr_mask; - bool is_lvl_trigger = false; - - /* disable interrupt */ - ioapic_gsi_mask_irq(phys_irq); - - /* build physical IOAPIC RTE */ - rte = ptirq_build_physical_rte(vm, entry); - intr_mask = rte.bits.intr_mask; - - /* update irq trigger mode according to info in guest */ - if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) { - is_lvl_trigger = true; - } - set_irq_trigger_mode(phys_irq, is_lvl_trigger); - - /* set rte entry when masked */ - rte.bits.intr_mask = IOAPIC_RTE_MASK_SET; - ioapic_set_rte(phys_irq, rte); - - if (intr_mask == IOAPIC_RTE_MASK_CLR) { - ioapic_gsi_unmask_irq(phys_irq); - } -} - -/* Main entry for PCI/Legacy device assignment with INTx, calling from vIOAPIC - * or vPIC - */ -int32_t ptirq_intx_pin_remap(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_ctlr) -{ - int32_t status = 0; - struct ptirq_remapping_info *entry = NULL; - DEFINE_INTX_SID(virt_sid, virt_gsi, vgsi_ctlr); - DEFINE_INTX_SID(alt_virt_sid, virt_gsi, vgsi_ctlr); - - /* - * virt pin could come from primary vPIC, secondary vPIC or vIOAPIC - * while phys pin is always means for physical IOAPIC. - * - * Device Model should pre-hold the mapping entries by calling - * ptirq_add_intx_remapping for UOS. - * - * For SOS(sos_vm), it adds the mapping entries at runtime, if the - * entry already be held by others, return error. - */ - - /* no remap for vuart intx */ - if (!is_vuart_intx(vm, virt_sid.intx_id.gsi)) { - /* query if we have virt to phys mapping */ - spinlock_obtain(&ptdev_lock); - entry = find_ptirq_entry(PTDEV_INTR_INTX, &virt_sid, vm); - if (entry == NULL) { - if (is_sos_vm(vm)) { - - /* for sos_vm, there is chance of vpin source switch - * between vPIC & vIOAPIC for one legacy phys_pin. - * - * here checks if there is already mapping entry from - * the other vpin source for legacy pin. If yes, then - * switch vpin source is needed - */ - if (virt_gsi < NR_LEGACY_PIN) { - - if (vgsi_ctlr == INTX_CTLR_PIC) { - alt_virt_sid.intx_id.ctlr = INTX_CTLR_IOAPIC; - } else { - alt_virt_sid.intx_id.ctlr = INTX_CTLR_PIC; - } - - entry = find_ptirq_entry(PTDEV_INTR_INTX, &alt_virt_sid, vm); - if (entry != NULL) { - uint32_t phys_gsi = virt_gsi; - - remove_intx_remapping(vm, alt_virt_sid.intx_id.gsi, - alt_virt_sid.intx_id.ctlr); - entry = add_intx_remapping(vm, virt_gsi, phys_gsi, vgsi_ctlr); - if (entry == NULL) { - pr_err("%s, add intx remapping failed", __func__); - status = -ENODEV; - } else { - dev_dbg(DBG_LEVEL_IRQ, - "IOAPIC gsi=%hhu pirq=%u vgsi=%d from %s to %s for vm%d", - entry->phys_sid.intx_id.gsi, - entry->allocated_pirq, entry->virt_sid.intx_id.gsi, - (vgsi_ctlr == INTX_CTLR_IOAPIC) ? "vPIC" : "vIOAPIC", - (vgsi_ctlr == INTX_CTLR_IOAPIC) ? "vIOPIC" : "vPIC", - entry->vm->vm_id); - } - } - } - - /* entry could be updated by above switch check */ - if (entry == NULL) { - uint32_t phys_gsi = virt_gsi; - - entry = add_intx_remapping(vm, virt_gsi, phys_gsi, vgsi_ctlr); - if (entry == NULL) { - pr_err("%s, add intx remapping failed", - __func__); - status = -ENODEV; - } - } - } else { - /* ptirq_intx_pin_remap is triggered by vPIC/vIOAPIC - * everytime a pin get unmask, here filter out pins - * not get mapped. - */ - status = -ENODEV; - } - } - spinlock_release(&ptdev_lock); - } else { - status = -EINVAL; - } - - if (status == 0) { - activate_physical_ioapic(vm, entry); - } - - return status; -} - -/* @pre vm != NULL - * except sos_vm, Device Model should call this function to pre-hold ptdev intx - * entries: - * - the entry is identified by phys_pin: - * one entry vs. one phys_pin - * - currently, one phys_pin can only be held by one pin source (vPIC or - * vIOAPIC) - */ -int32_t ptirq_add_intx_remapping(struct acrn_vm *vm, uint32_t virt_gsi, uint32_t phys_gsi, bool pic_pin) -{ - struct ptirq_remapping_info *entry; - enum intx_ctlr vgsi_ctlr = pic_pin ? INTX_CTLR_PIC : INTX_CTLR_IOAPIC; - - spinlock_obtain(&ptdev_lock); - entry = add_intx_remapping(vm, virt_gsi, phys_gsi, vgsi_ctlr); - spinlock_release(&ptdev_lock); - - return (entry != NULL) ? 0 : -ENODEV; -} - -/* - * @pre vm != NULL - */ -void ptirq_remove_intx_remapping(const struct acrn_vm *vm, uint32_t virt_gsi, bool pic_pin) -{ - enum intx_ctlr vgsi_ctlr = pic_pin ? INTX_CTLR_PIC : INTX_CTLR_IOAPIC; - - spinlock_obtain(&ptdev_lock); - remove_intx_remapping(vm, virt_gsi, vgsi_ctlr); - spinlock_release(&ptdev_lock); -} - -/* - * @pre vm != NULL - */ -void ptirq_remove_msix_remapping(const struct acrn_vm *vm, uint16_t phys_bdf, - uint32_t vector_count) -{ - uint32_t i; - - for (i = 0U; i < vector_count; i++) { - spinlock_obtain(&ptdev_lock); - remove_msix_remapping(vm, phys_bdf, i); - spinlock_release(&ptdev_lock); - } -} - -/* - * @pre vm != NULL - */ -void ptirq_remove_configured_intx_remappings(const struct acrn_vm *vm) -{ - const struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id); - uint32_t i; - - for (i = 0; i < vm_config->pt_intx_num; i++) { - ptirq_remove_intx_remapping(vm, vm_config->pt_intx[i].virt_gsi, false); - } -} diff --git a/hypervisor/arch/x86/guest/ept.c b/hypervisor/arch/x86/guest/ept.c index 4643d12b3d..f8dcbda9a7 100644 --- a/hypervisor/arch/x86/guest/ept.c +++ b/hypervisor/arch/x86/guest/ept.c @@ -6,16 +6,20 @@ #include #include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include #define DBG_LEVEL_EPT 6U diff --git a/hypervisor/arch/x86/guest/guest_memory.c b/hypervisor/arch/x86/guest/guest_memory.c index 068c332337..7eae784f4f 100644 --- a/hypervisor/arch/x86/guest/guest_memory.c +++ b/hypervisor/arch/x86/guest/guest_memory.c @@ -6,13 +6,13 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include struct page_walk_info { diff --git a/hypervisor/arch/x86/guest/hyperv.c b/hypervisor/arch/x86/guest/hyperv.c index 458dbb4f33..64305bd2b3 100644 --- a/hypervisor/arch/x86/guest/hyperv.c +++ b/hypervisor/arch/x86/guest/hyperv.c @@ -8,10 +8,11 @@ */ #include -#include +#include #include -#include -#include +#include +#include +#include #define DBG_LEVEL_HYPERV 6U @@ -66,13 +67,13 @@ hyperv_get_tsc_scale_offset(struct acrn_vm *vm, uint64_t *scale, uint64_t *offse * ReferenceTime is in 100ns units * * ReferenceTime = - * VirtualTsc / (get_tsc_khz() * 1000) * 1000000000 / 100 + * VirtualTsc / (get_cpu_freq() * 1000) * 1000000000 / 100 * + TscOffset */ - uint64_t ret, khz = get_tsc_khz(); + uint64_t ret, khz = get_cpu_freq(); - /* ret = (10000U << 64U) / get_tsc_khz() */ + /* ret = (10000U << 64U) / get_cpu_freq() */ ret = u64_shl64_div_u64(10000U, khz); dev_dbg(DBG_LEVEL_HYPERV, "%s, ret = 0x%lx", __func__, ret); @@ -119,7 +120,7 @@ hyperv_get_ref_count(struct acrn_vm *vm) uint64_t tsc, tsc_scale, tsc_offset, ret; /* currently only "use tsc offsetting" is set to 1 */ - tsc = rdtsc() + exec_vmread64(VMX_TSC_OFFSET_FULL); + tsc = get_cpu_cycles() + exec_vmread64(VMX_TSC_OFFSET_FULL); hyperv_get_tsc_scale_offset(vm, &tsc_scale, &tsc_offset); diff --git a/hypervisor/arch/x86/guest/instr_emul.c b/hypervisor/arch/x86/guest/instr_emul.c index 601287fb72..780b4a5ec4 100644 --- a/hypervisor/arch/x86/guest/instr_emul.c +++ b/hypervisor/arch/x86/guest/instr_emul.c @@ -30,11 +30,12 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #define CPU_REG_FIRST CPU_REG_RAX diff --git a/hypervisor/arch/x86/guest/pm.c b/hypervisor/arch/x86/guest/pm.c index 36fa180e85..742227c18c 100644 --- a/hypervisor/arch/x86/guest/pm.c +++ b/hypervisor/arch/x86/guest/pm.c @@ -5,13 +5,13 @@ */ #include -#include -#include -#include +#include +#include +#include #include #include -#include -#include +#include +#include int32_t validate_pstate(const struct acrn_vm *vm, uint64_t perf_ctl) { diff --git a/hypervisor/arch/x86/guest/splitlock.c b/hypervisor/arch/x86/guest/splitlock.c index cd6e99489f..4879e81081 100644 --- a/hypervisor/arch/x86/guest/splitlock.c +++ b/hypervisor/arch/x86/guest/splitlock.c @@ -5,14 +5,16 @@ */ #include -#include -#include +#include +#include +#include #include +#include #include -#include +#include #include #include -#include +#include static bool is_guest_ac_enabled(struct acrn_vcpu *vcpu) { diff --git a/hypervisor/arch/x86/guest/trusty.c b/hypervisor/arch/x86/guest/trusty.c index 348ca9df2c..2c4a590365 100644 --- a/hypervisor/arch/x86/guest/trusty.c +++ b/hypervisor/arch/x86/guest/trusty.c @@ -5,18 +5,18 @@ */ #include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include #define TRUSTY_VERSION 1U #define TRUSTY_VERSION_2 2U diff --git a/hypervisor/arch/x86/guest/ucode.c b/hypervisor/arch/x86/guest/ucode.c index 946997e994..13cc07f742 100644 --- a/hypervisor/arch/x86/guest/ucode.c +++ b/hypervisor/arch/x86/guest/ucode.c @@ -6,13 +6,18 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #define MICRO_CODE_SIZE_MAX 0x40000U diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index bf6a049fe4..560654cd2a 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -6,18 +6,19 @@ #include #include -#include -#include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include -#include +#include /* stack_frame is linked with the sequence of stack operation in arch_switch_to() */ struct stack_frame { diff --git a/hypervisor/arch/x86/guest/vcpuid.c b/hypervisor/arch/x86/guest/vcpuid.c index 7b48ca6d2e..ed4a4b23c7 100644 --- a/hypervisor/arch/x86/guest/vcpuid.c +++ b/hypervisor/arch/x86/guest/vcpuid.c @@ -6,14 +6,14 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include +#include static inline const struct vcpuid_entry *local_find_vcpuid_entry(const struct acrn_vcpu *vcpu, uint32_t leaf, uint32_t subleaf) @@ -106,8 +106,6 @@ static inline int32_t set_vcpuid_entry(struct acrn_vm *vm, static void init_vcpuid_entry(uint32_t leaf, uint32_t subleaf, uint32_t flags, struct vcpuid_entry *entry) { - struct cpuinfo_x86 *cpu_info; - entry->leaf = leaf; entry->subleaf = subleaf; entry->flags = flags; @@ -171,13 +169,12 @@ static void init_vcpuid_entry(uint32_t leaf, uint32_t subleaf, break; case 0x16U: - cpu_info = get_pcpu_info(); - if (cpu_info->cpuid_level >= 0x16U) { + if (pcpu_cpuid_level() >= 0x16U) { /* call the cpuid when 0x16 is supported */ cpuid_subleaf(leaf, subleaf, &entry->eax, &entry->ebx, &entry->ecx, &entry->edx); } else { /* Use the tsc to derive the emulated 0x16U cpuid. */ - entry->eax = (uint32_t) (get_tsc_khz() / 1000U); + entry->eax = (uint32_t) (get_cpu_freq() / 1000U); entry->ebx = entry->eax; /* Bus frequency: hard coded to 100M */ entry->ecx = 100U; @@ -230,7 +227,7 @@ static void init_vcpuid_entry(uint32_t leaf, uint32_t subleaf, * EBX, ECX, EDX: RESERVED (reserved fields are set to zero). */ case 0x40000010U: - entry->eax = get_tsc_khz(); + entry->eax = get_cpu_freq(); entry->ebx = 0U; entry->ecx = 0U; entry->edx = 0U; @@ -348,10 +345,9 @@ int32_t set_vcpuid_entries(struct acrn_vm *vm) struct vcpuid_entry entry; uint32_t limit; uint32_t i, j; - struct cpuinfo_x86 *cpu_info = get_pcpu_info(); init_vcpuid_entry(0U, 0U, 0U, &entry); - if (cpu_info->cpuid_level < 0x16U) { + if (pcpu_cpuid_level() < 0x16U) { /* The cpuid with zero leaf returns the max level. Emulate that the 0x16U is supported */ entry.eax = 0x16U; } diff --git a/hypervisor/arch/x86/guest/ve820.c b/hypervisor/arch/x86/guest/ve820.c index 77fd53361f..b414eb11f3 100644 --- a/hypervisor/arch/x86/guest/ve820.c +++ b/hypervisor/arch/x86/guest/ve820.c @@ -4,13 +4,13 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include +#include +#include +#include #include #include #include -#include +#include #define ENTRY_HPA1_LOW_PART1 2U #define ENTRY_HPA1_LOW_PART2 4U diff --git a/hypervisor/arch/x86/guest/virq.c b/hypervisor/arch/x86/guest/virq.c index a3eb883e9e..ade3eed68f 100644 --- a/hypervisor/arch/x86/guest/virq.c +++ b/hypervisor/arch/x86/guest/virq.c @@ -6,15 +6,19 @@ #include #include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -32,6 +36,17 @@ #define EXCEPTION_ABORT 2U #define EXCEPTION_INTERRUPT 3U +/* RFLAGS */ +#define HV_ARCH_VCPU_RFLAGS_TF (1UL<<8U) +#define HV_ARCH_VCPU_RFLAGS_IF (1UL<<9U) +#define HV_ARCH_VCPU_RFLAGS_RF (1UL<<16U) + +/* Interruptability State info */ + +#define HV_ARCH_VCPU_BLOCKED_BY_NMI (1UL<<3U) +#define HV_ARCH_VCPU_BLOCKED_BY_MOVSS (1UL<<1U) +#define HV_ARCH_VCPU_BLOCKED_BY_STI (1UL<<0U) + static const uint16_t exception_type[32] = { [0] = VMX_INT_TYPE_HW_EXP, [1] = VMX_INT_TYPE_HW_EXP, diff --git a/hypervisor/arch/x86/guest/virtual_cr.c b/hypervisor/arch/x86/guest/virtual_cr.c index 01ab18c057..aec81861dc 100644 --- a/hypervisor/arch/x86/guest/virtual_cr.c +++ b/hypervisor/arch/x86/guest/virtual_cr.c @@ -8,16 +8,19 @@ #include #include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -107,7 +110,6 @@ static uint64_t cr0_reserved_bits_mask; static int32_t load_pdptrs(const struct acrn_vcpu *vcpu) { uint64_t guest_cr3 = exec_vmread(VMX_GUEST_CR3); - struct cpuinfo_x86 *cpu_info = get_pcpu_info(); int32_t ret = 0; uint64_t pdpte[4]; /* Total four PDPTE */ uint64_t rsvd_bits_mask; @@ -123,7 +125,7 @@ static int32_t load_pdptrs(const struct acrn_vcpu *vcpu) /* Check if any of the PDPTEs sets both the P flag * and any reserved bit */ - maxphyaddr = cpu_info->phys_bits; + maxphyaddr = pcpu_physaddr_bits(); /* reserved bits: 1~2, 5~8, maxphyaddr ~ 63 */ rsvd_bits_mask = (63U < maxphyaddr) ? 0UL : (((1UL << (63U - maxphyaddr + 1U)) - 1UL) << maxphyaddr); rsvd_bits_mask |= PAE_PDPTE_FIXED_RESVD_BITS; diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 7f24363830..26c706d9eb 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -31,19 +31,21 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include "vlapic_priv.h" #define VLAPIC_VERBOS 0 @@ -257,9 +259,7 @@ static void vlapic_init_timer(struct acrn_vlapic *vlapic) vtimer = &vlapic->vtimer; (void)memset(vtimer, 0U, sizeof(struct vlapic_timer)); - initialize_timer(&vtimer->timer, - vlapic_timer_expired, vlapic2vcpu(vlapic), - 0UL, 0, 0UL); + initialize_timer(&vtimer->timer, vlapic_timer_expired, vlapic2vcpu(vlapic), 0UL, 0UL); } /** @@ -271,16 +271,14 @@ static void vlapic_reset_timer(struct acrn_vlapic *vlapic) timer = &vlapic->vtimer.timer; del_timer(timer); - timer->mode = TICK_MODE_ONESHOT; - timer->fire_tsc = 0UL; - timer->period_in_cycle = 0UL; + update_timer(timer, 0UL, 0UL); } static bool set_expiration(struct acrn_vlapic *vlapic) { - uint64_t now = rdtsc(); - uint64_t delta; + uint64_t now = get_cpu_cycles(); + uint64_t delta, timeout, period_in_cycle = 0UL; struct vlapic_timer *vtimer; struct hv_timer *timer; uint32_t tmicr, divisor_shift; @@ -297,9 +295,10 @@ set_expiration(struct acrn_vlapic *vlapic) timer = &vtimer->timer; if (vlapic_lvtt_period(vlapic)) { - timer->period_in_cycle = delta; + period_in_cycle = delta; } - timer->fire_tsc = now + delta; + timeout = now + delta; + update_timer(timer, timeout, period_in_cycle); ret = true; } return ret; @@ -319,10 +318,7 @@ static void vlapic_update_lvtt(struct acrn_vlapic *vlapic, * the timer mode disarms the local APIC timer. */ del_timer(timer); - timer->mode = (timer_mode == APIC_LVTT_TM_PERIODIC) ? - TICK_MODE_PERIODIC: TICK_MODE_ONESHOT; - timer->fire_tsc = 0UL; - timer->period_in_cycle = 0UL; + update_timer(timer, 0UL, 0UL); vtimer->mode = timer_mode; } @@ -330,19 +326,17 @@ static void vlapic_update_lvtt(struct acrn_vlapic *vlapic, static uint32_t vlapic_get_ccr(const struct acrn_vlapic *vlapic) { - uint64_t now = rdtsc(); + uint64_t shifted_delta; uint32_t remain_count = 0U; const struct vlapic_timer *vtimer; vtimer = &vlapic->vtimer; if ((vtimer->tmicr != 0U) && (!vlapic_lvtt_tsc_deadline(vlapic))) { - uint64_t fire_tsc = vtimer->timer.fire_tsc; - - if (now < fire_tsc) { + if (!timer_expired(&vtimer->timer, get_cpu_cycles(), &shifted_delta)) { uint32_t divisor_shift = vtimer->divisor_shift; - uint64_t shifted_delta = - (fire_tsc - now) >> divisor_shift; + + shifted_delta = shifted_delta >> divisor_shift; remain_count = (uint32_t)shifted_delta; } } @@ -375,7 +369,7 @@ static void vlapic_write_icrtmr(struct acrn_vlapic *vlapic) del_timer(&vtimer->timer); if (set_expiration(vlapic)) { /* vlapic_init_timer has been called, - * and timer->fire_tsc is not 0, here + * and timer->timeout is not 0,here * add_timer should not return error */ (void)add_timer(&vtimer->timer); @@ -402,7 +396,7 @@ uint64_t vlapic_get_tsc_deadline_msr(const struct acrn_vlapic *vlapic) } else if (!vlapic_lvtt_tsc_deadline(vlapic)) { ret = 0UL; } else { - ret = (vlapic->vtimer.timer.fire_tsc == 0UL) ? 0UL : + ret = timer_expired(&vlapic->vtimer.timer, get_cpu_cycles(), NULL) ? 0UL : vcpu_get_guest_msr(vcpu, MSR_IA32_TSC_DEADLINE); } @@ -441,14 +435,14 @@ void vlapic_set_tsc_deadline_msr(struct acrn_vlapic *vlapic, uint64_t val_arg) if (val != 0UL) { /* transfer guest tsc to host tsc */ val -= exec_vmread64(VMX_TSC_OFFSET_FULL); - timer->fire_tsc = val; + update_timer(timer, val, 0UL); /* vlapic_init_timer has been called, - * and timer->fire_tsc is not 0,here + * and timer->timeout is not 0, here * add_timer should not return error */ (void)add_timer(timer); } else { - timer->fire_tsc = 0UL; + update_timer(timer, 0UL, 0UL); } } else { /* No action required */ @@ -1374,7 +1368,7 @@ vlapic_write_svr(struct acrn_vlapic *vlapic) if (vlapic_lvtt_period(vlapic)) { if (set_expiration(vlapic)) { /* vlapic_init_timer has been called, - * and timer->fire_tsc is not 0,here + * and timer->timeout is not 0,here * add_timer should not return error */ (void)add_timer(&vlapic->vtimer.timer); @@ -2036,10 +2030,6 @@ static void vlapic_timer_expired(void *data) if (!vlapic_lvtt_masked(vlapic)) { vlapic_set_intr(vcpu, lapic->lvt[APIC_LVT_TIMER].v & APIC_LVTT_VECTOR, LAPIC_TRIG_EDGE); } - - if (!vlapic_lvtt_period(vlapic)) { - vlapic->vtimer.timer.fire_tsc = 0UL; - } } /* diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 8f61f10ef8..ee98325a12 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -7,35 +7,35 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include #include -#include -#include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include #include #include -#include -#include +#include +#include #include -#include +#include #include -#include +#include #include -#include -#include +#include +#include #include -#include +#include /* Local variables */ @@ -411,6 +411,23 @@ static uint64_t lapic_pt_enabled_pcpu_bitmap(struct acrn_vm *vm) return bitmap; } +/* + * @pre vm != NULL + */ +static void ptintr_remove_configured_intx_remappings(struct acrn_vm *vm) +{ + const struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id); + struct ptintr_rmv_args intx_rmv; + uint32_t i; + + for (i = 0; i < vm_config->pt_intx_num; i++) { + intx_rmv.intr_type = PTDEV_INTR_INTX; + intx_rmv.intx.virt_gsi = vm_config->pt_intx[i].virt_gsi; + intx_rmv.intx.virt_ctlr = INTX_CTLR_IOAPIC; + ptintr_remove_and_unmap(vm, &intx_rmv); + } +} + /** * @pre vm_id < CONFIG_MAX_VM_NUM && vm_config != NULL && rtn_vm != NULL * @pre vm->state == VM_POWERED_OFF @@ -540,11 +557,18 @@ int32_t create_vm(uint16_t vm_id, uint64_t pcpu_bitmap, struct acrn_vm_config *v if (status == 0) { uint32_t i; + struct ptintr_add_args intx_add; + for (i = 0; i < vm_config->pt_intx_num; i++) { - status = ptirq_add_intx_remapping(vm, vm_config->pt_intx[i].virt_gsi, - vm_config->pt_intx[i].phys_gsi, false); + intx_add.intr_type = PTDEV_INTR_INTX; + intx_add.intx.virt_gsi = vm_config->pt_intx[i].virt_gsi; + intx_add.intx.virt_ctlr = INTX_CTLR_IOAPIC; + intx_add.intx.phys_gsi = vm_config->pt_intx[i].phys_gsi; + intx_add.intx.phys_ctlr = INTX_CTLR_IOAPIC; + status = ptintr_add(vm, &intx_add); + if (status != 0) { - ptirq_remove_configured_intx_remappings(vm); + ptintr_remove_configured_intx_remappings(vm); break; } } @@ -635,7 +659,7 @@ int32_t shutdown_vm(struct acrn_vm *vm) sbuf_reset(); } - ptirq_remove_configured_intx_remappings(vm); + ptintr_remove_configured_intx_remappings(vm); deinit_legacy_vuarts(vm); diff --git a/hypervisor/arch/x86/guest/vm_reset.c b/hypervisor/arch/x86/guest/vm_reset.c index 7ec419c576..4605e29955 100644 --- a/hypervisor/arch/x86/guest/vm_reset.c +++ b/hypervisor/arch/x86/guest/vm_reset.c @@ -4,12 +4,12 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include +#include +#include +#include #include -#include -#include +#include +#include /** * @pre vm != NULL diff --git a/hypervisor/arch/x86/guest/vmcall.c b/hypervisor/arch/x86/guest/vmcall.c index 0a34865687..8b51b3c394 100644 --- a/hypervisor/arch/x86/guest/vmcall.c +++ b/hypervisor/arch/x86/guest/vmcall.c @@ -6,9 +6,10 @@ #include #include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/hypervisor/arch/x86/guest/vmcs.c b/hypervisor/arch/x86/guest/vmcs.c index 2dec333401..902a6c5671 100644 --- a/hypervisor/arch/x86/guest/vmcs.c +++ b/hypervisor/arch/x86/guest/vmcs.c @@ -7,16 +7,15 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include /* rip, rsp, ia32_efer and rflags are written to VMCS in start_vcpu */ diff --git a/hypervisor/arch/x86/guest/vmexit.c b/hypervisor/arch/x86/guest/vmexit.c index 9b2c1b2b97..328332c0ac 100644 --- a/hypervisor/arch/x86/guest/vmexit.c +++ b/hypervisor/arch/x86/guest/vmexit.c @@ -6,20 +6,24 @@ #include #include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include /* * According to "SDM APPENDIX C VMX BASIC EXIT REASONS", diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index cf5d6dbc38..5a446ad3ea 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -6,18 +6,20 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #define INTERCEPT_DISABLE (0U) #define INTERCEPT_READ (1U << 0U) @@ -601,7 +603,7 @@ static void set_guest_tsc(struct acrn_vcpu *vcpu, uint64_t guest_tsc) { uint64_t tsc_delta, tsc_offset_delta, tsc_adjust; - tsc_delta = guest_tsc - rdtsc(); + tsc_delta = guest_tsc - get_cpu_cycles(); /* the delta between new and existing TSC_OFFSET */ tsc_offset_delta = tsc_delta - exec_vmread64(VMX_TSC_OFFSET_FULL); @@ -698,7 +700,9 @@ static void set_guest_ia32_misc_enalbe(struct acrn_vcpu *vcpu, uint64_t v) if ((ecx & CPUID_ECX_SSE3) == 0U) { vcpu_inject_gp(vcpu, 0U); update_vmsr = false; - } else if ((!has_monitor_cap()) && (!is_apl_platform())) { + /* APL: family 0x6U model 0x5cU */ + } else if ((!has_monitor_cap()) && + !((pcpu_family_id() == 0x6U) && (pcpu_model_id() == 0x5cU))) { msr_value = msr_read(MSR_IA32_MISC_ENABLE) & ~MSR_IA32_MISC_ENABLE_MONITOR_ENA; msr_value |= v & MSR_IA32_MISC_ENABLE_MONITOR_ENA; /* This will not change the return value of has_monitor_cap() since the feature values diff --git a/hypervisor/arch/x86/guest/vmtrr.c b/hypervisor/arch/x86/guest/vmtrr.c index 119de8b542..d9311b6dcf 100644 --- a/hypervisor/arch/x86/guest/vmtrr.c +++ b/hypervisor/arch/x86/guest/vmtrr.c @@ -4,12 +4,12 @@ */ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #define MTRR_FIXED_RANGE_ALL_WB (MTRR_MEM_TYPE_WB \ diff --git a/hypervisor/arch/x86/guest/vmx_asm.S b/hypervisor/arch/x86/guest/vmx_asm.S index 86d9c96fca..17211d7a4b 100644 --- a/hypervisor/arch/x86/guest/vmx_asm.S +++ b/hypervisor/arch/x86/guest/vmx_asm.S @@ -4,9 +4,9 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include +#include +#include +#include /* NOTE: * diff --git a/hypervisor/arch/x86/guest/vmx_io.c b/hypervisor/arch/x86/guest/vmx_io.c index 0b79fed442..9af7ce99fd 100644 --- a/hypervisor/arch/x86/guest/vmx_io.c +++ b/hypervisor/arch/x86/guest/vmx_io.c @@ -6,15 +6,15 @@ #include #include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/hypervisor/arch/x86/idt.S b/hypervisor/arch/x86/idt.S index 798a94f855..d9e0e16a4d 100644 --- a/hypervisor/arch/x86/idt.S +++ b/hypervisor/arch/x86/idt.S @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include .altmacro diff --git a/hypervisor/arch/x86/init.c b/hypervisor/arch/x86/init.c index 3d2b6259a4..631272d0f8 100644 --- a/hypervisor/arch/x86/init.c +++ b/hypervisor/arch/x86/init.c @@ -5,15 +5,34 @@ */ #include -#include #include -#include +#include #include -#include -#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include /* boot_regs store the multiboot info magic and address, defined in @@ -31,6 +50,8 @@ extern uint32_t boot_regs[2]; : "r"(rsp), "rm"(SP_BOTTOM_MAGIC), "a"(to)); \ } +static uint64_t start_cycle __attribute__((__section__(".bss_noinit"))); + /*TODO: move into debug module */ static void init_debug_pre(void) { @@ -61,13 +82,163 @@ static void init_guest_mode(uint16_t pcpu_id) launch_vms(pcpu_id); } +static void print_hv_banner(void) +{ + const char *boot_msg = "ACRN Hypervisor\n\r"; + + /* Print the boot message */ + printf(boot_msg); +} + +static void enable_ac_for_splitlock(void) +{ +#ifndef CONFIG_ENFORCE_TURNOFF_AC + uint64_t test_ctl; + + if (has_core_cap(1U << 5U)) { + test_ctl = msr_read(MSR_TEST_CTL); + test_ctl |= (1U << 29U); + msr_write(MSR_TEST_CTL, test_ctl); + } +#endif /*CONFIG_ENFORCE_TURNOFF_AC*/ +} + +static void init_pcpu_xsave(void) +{ + uint64_t val64; + uint64_t xcr0, xss; + uint32_t eax, ebx, ecx, edx; + + CPU_CR_READ(cr4, &val64); + val64 |= CR4_OSXSAVE; + CPU_CR_WRITE(cr4, val64); + + if (get_pcpu_id() == BSP_CPU_ID) { + cpuid_subleaf(CPUID_FEATURES, 0x0U, &eax, &ebx, &ecx, &edx); + + /* if set, update it */ + if ((ecx & CPUID_ECX_OSXSAVE) != 0U) { + pcpu_set_cap(X86_FEATURE_OSXSAVE); + + /* set xcr0 and xss with the componets bitmap get from cpuid */ + cpuid_subleaf(CPUID_XSAVE_FEATURES, 0U, &eax, &ebx, &ecx, &edx); + xcr0 = ((uint64_t)edx << 32U) + eax; + cpuid_subleaf(CPUID_XSAVE_FEATURES, 1U, &eax, &ebx, &ecx, &edx); + xss = ((uint64_t)edx << 32U) + ecx; + write_xcr(0, xcr0); + msr_write(MSR_IA32_XSS, xss); + + /* get xsave area size, containing all the state components + * corresponding to bits currently set in XCR0 | IA32_XSS */ + cpuid_subleaf(CPUID_XSAVE_FEATURES, 1U, &eax, &ebx, &ecx, &edx); + if (ebx > XSAVE_STATE_AREA_SIZE) { + panic("XSAVE area (%d bytes) exceeds the pre-allocated 4K region\n", ebx); + } + } + } +} + static void init_pcpu_comm_post(void) { uint16_t pcpu_id; pcpu_id = get_pcpu_id(); - init_pcpu_post(pcpu_id); +#ifdef STACK_PROTECTOR + set_fs_base(); +#endif + load_gdtr_and_tr(); + + enable_ac_for_splitlock(); + + init_pcpu_xsave(); + + if (pcpu_id == BSP_CPU_ID) { + /* Print Hypervisor Banner */ + print_hv_banner(); + + /* Calibrate TSC Frequency */ + calibrate_tsc(); + + pr_acrnlog("HV version %s-%s-%s %s (daily tag:%s) %s@%s build by %s%s, start time %luus", + HV_FULL_VERSION, + HV_BUILD_TIME, HV_BUILD_VERSION, HV_BUILD_TYPE, + HV_DAILY_TAG, HV_BUILD_SCENARIO, HV_BUILD_BOARD, + HV_BUILD_USER, HV_CONFIG_TOOL, cycles_to_us(start_cycle)); + + pr_acrnlog("API version %u.%u", HV_API_MAJOR_VERSION, HV_API_MINOR_VERSION); + + pr_acrnlog("Detect processor: %s", pcpu_model_name()); + + pr_dbg("Core %hu is up", BSP_CPU_ID); + + /* Warn for security feature not ready */ + if (!check_cpu_security_cap()) { + pr_fatal("SECURITY WARNING!!!!!!"); + pr_fatal("Please apply the latest CPU uCode patch!"); + } + + /* Initialize interrupts */ + init_interrupt(BSP_CPU_ID); + + timer_init(); + setup_notification(); + setup_pi_notification(); + + if (init_iommu() != 0) { + panic("failed to initialize iommu!"); + } + +#ifdef CONFIG_IVSHMEM_ENABLED + init_ivshmem_shared_memory(); +#endif + init_pci_pdev_list(); /* init_iommu must come before this */ + ptintr_init(); + + if (init_sgx() != 0) { + panic("failed to initialize sgx!"); + } + + /* + * Reserve memory from platform E820 for EPT 4K pages for all VMs + */ +#ifdef CONFIG_LAST_LEVEL_EPT_AT_BOOT + reserve_buffer_for_ept_pages(); +#endif + /* Start all secondary cores */ + if (!start_pcpus(AP_MASK)) { + panic("Failed to start all secondary cores!"); + } + + ASSERT(get_pcpu_id() == BSP_CPU_ID, ""); + + init_software_sram(true); + } else { + pr_dbg("Core %hu is up", pcpu_id); + + pr_warn("Skipping VM configuration check which should be done before building HV binary."); + + init_software_sram(false); + + /* Initialize secondary processor interrupts. */ + init_interrupt(pcpu_id); + + timer_init(); + ptintr_init(); + + /* Wait for boot processor to signal all secondary cores to continue */ + wait_all_pcpus_run(); + } + + init_sched(pcpu_id); + +#ifdef CONFIG_RDT_ENABLED + setup_clos(pcpu_id); +#endif + + enable_smep(); + enable_smap(); + init_debug_post(pcpu_id); init_guest_mode(pcpu_id); run_idle_thread(); @@ -81,12 +252,56 @@ static void init_misc(void) } } +static bool init_percpu_lapic_id(void) +{ + uint16_t i, pcpu_num; + uint32_t lapic_id_array[MAX_PCPU_NUM]; + bool success = false; + + /* Save all lapic_id detected via parse_mdt in lapic_id_array */ + pcpu_num = parse_madt(lapic_id_array); + + if ((pcpu_num != 0U) && (pcpu_num <= MAX_PCPU_NUM)) { + set_pcpu_nums(pcpu_num); + for (i = 0U; i < pcpu_num; i++) { + per_cpu(lapic_id, i) = lapic_id_array[i]; + } + success = true; + } + + return success; +} + +static uint16_t get_pcpu_id_from_lapic_id(uint32_t lapic_id) +{ + uint16_t i; + uint16_t pcpu_id = INVALID_CPU_ID; + + for (i = 0U; i < get_pcpu_nums(); i++) { + if (per_cpu(lapic_id, i) == lapic_id) { + pcpu_id = i; + break; + } + } + + return pcpu_id; +} + +static void init_pcpu_state(uint16_t pcpu_id) +{ + set_active_pcpu_bitmap(pcpu_id); + + /* Set state for this CPU to initializing */ + pcpu_set_current_state(pcpu_id, PCPU_STATE_INITIALIZING); +} + /* NOTE: this function is using temp stack, and after SWITCH_TO(runtime_sp, to) * it will switch to runtime stack. */ void init_primary_pcpu(void) { uint64_t rsp; + int32_t ret; /* Clear BSS */ (void)memset(&ld_bss_start, 0U, (size_t)(&ld_bss_end - &ld_bss_start)); @@ -99,7 +314,58 @@ void init_primary_pcpu(void) panic("Multiboot info error!"); } - init_pcpu_pre(true); + start_cycle = get_cpu_cycles(); + + /* Get CPU capabilities thru CPUID, including the physical address bit + * limit which is required for initializing paging. + */ + init_pcpu_capabilities(); + + if (detect_hardware_support() != 0) { + panic("hardware not support!"); + } + + load_pcpu_state_data(); + + /* Initialize the hypervisor paging */ + init_e820(); + init_paging(); + + /* + * Need update uart_base_address here for vaddr2paddr mapping may changed + * WARNNING: DO NOT CALL PRINTF BETWEEN ENABLE PAGING IN init_paging AND HERE! + */ + uart16550_init(false); + + early_init_lapic(); + +#ifdef CONFIG_ACPI_PARSE_ENABLED + ret = acpi_fixup(); + if (ret != 0) { + panic("failed to parse/fix up ACPI table!"); + } +#endif + + if (!init_percpu_lapic_id()) { + panic("failed to init_percpu_lapic_id!"); + } + + ret = init_ioapic_id_info(); + if (ret != 0) { + panic("System IOAPIC info is incorrect!"); + } + +#ifdef CONFIG_RDT_ENABLED + init_rdt_info(); +#endif + + /* NOTE: this must call after MMCONFIG is parsed in acpi_fixup() and before APs are INIT. + * We only support platform with MMIO based CFG space access. + * IO port access only support in debug version. + */ + pci_switch_to_mmio_cfg_ops(); + + init_pcpu_state(BSP_CPU_ID); init_seed(); init_misc(); @@ -112,6 +378,21 @@ void init_primary_pcpu(void) void init_secondary_pcpu(void) { - init_pcpu_pre(false); + uint16_t pcpu_id; + + /* Switch this CPU to use the same page tables set-up by the + * primary/boot CPU + */ + enable_paging(); + + early_init_lapic(); + + pcpu_id = get_pcpu_id_from_lapic_id(get_cur_lapic_id()); + if (pcpu_id >= MAX_PCPU_NUM) { + panic("Invalid pCPU ID!"); + } + + init_pcpu_state(pcpu_id); + init_pcpu_comm_post(); } diff --git a/hypervisor/arch/x86/ioapic.c b/hypervisor/arch/x86/ioapic.c index 57fbea7232..612c5e0853 100644 --- a/hypervisor/arch/x86/ioapic.c +++ b/hypervisor/arch/x86/ioapic.c @@ -6,22 +6,54 @@ #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include #include #include +#define DBG_LEVEL_IOAPIC 6U + +static union ioapic_rte saved_rte[CONFIG_MAX_IOAPIC_NUM][CONFIG_MAX_IOAPIC_LINES]; + +struct ioapic_info ioapic_array[CONFIG_MAX_IOAPIC_NUM]; + +spinlock_t ioapic_lock; + #define NR_MAX_GSI (CONFIG_MAX_IOAPIC_NUM * CONFIG_MAX_IOAPIC_LINES) +#define DEFAULT_DEST_MODE IOAPIC_RTE_DESTMODE_LOGICAL +#define DEFAULT_DELIVERY_MODE IOAPIC_RTE_DELMODE_LOPRI + +/* + * is_valid is by default false when all the + * static variables, part of .bss, are initialized to 0s + * It is set to true, if the corresponding + * gsi falls in ranges identified by IOAPIC data + * in ACPI MADT in ioapic_setup_irqs. + */ + +struct gsi_table { + bool is_valid; + struct { + uint8_t acpi_id; + uint8_t index; + uint32_t pin; + void *base_addr; + } ioapic_info; +}; + static struct gsi_table gsi_table_data[NR_MAX_GSI]; static uint32_t ioapic_max_nr_gsi; -static spinlock_t ioapic_lock = { .head = 0U, .tail = 0U, }; - -static union ioapic_rte saved_rte[CONFIG_MAX_IOAPIC_NUM][CONFIG_MAX_IOAPIC_LINES]; +static uint8_t ioapic_num; static const uint32_t legacy_irq_trigger_mode[NR_LEGACY_PIN] = { IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ2*/ @@ -61,9 +93,6 @@ static const uint32_t pic_ioapic_pin_map[NR_LEGACY_PIN] = { 15U, /* pin15*/ }; -static struct ioapic_info ioapic_array[CONFIG_MAX_IOAPIC_NUM]; -static uint8_t ioapic_num; - uint32_t get_pic_pin_from_ioapic_pin(uint32_t pin_index) { uint32_t pin_id = INVALID_INTERRUPT_PIN; @@ -73,12 +102,6 @@ uint32_t get_pic_pin_from_ioapic_pin(uint32_t pin_index) return pin_id; } -uint8_t get_platform_ioapic_info (struct ioapic_info **plat_ioapic_info) -{ - *plat_ioapic_info = ioapic_array; - return ioapic_num; -} - uint8_t get_gsi_to_ioapic_index(uint32_t gsi) { return gsi_table_data[gsi].ioapic_info.index; @@ -98,16 +121,7 @@ uint32_t get_max_nr_gsi(void) return ioapic_max_nr_gsi; } -static void *map_ioapic(uint64_t ioapic_paddr) -{ - /* At some point we may need to translate this paddr to a vaddr. - * 1:1 mapping for now. - */ - return hpa2hva(ioapic_paddr); -} - -static inline uint32_t -ioapic_read_reg32(void *ioapic_base, const uint32_t offset) +static uint32_t ioapic_read_reg32(void *ioapic_base, const uint32_t offset) { uint32_t v; uint64_t rflags; @@ -123,8 +137,7 @@ ioapic_read_reg32(void *ioapic_base, const uint32_t offset) return v; } -static inline void -ioapic_write_reg32(void *ioapic_base, const uint32_t offset, const uint32_t value) +static void ioapic_write_reg32(void *ioapic_base, const uint32_t offset, const uint32_t value) { uint64_t rflags; @@ -138,25 +151,7 @@ ioapic_write_reg32(void *ioapic_base, const uint32_t offset, const uint32_t valu spinlock_irqrestore_release(&ioapic_lock, rflags); } -/** - * @pre apic_id < 2 - */ -static inline uint64_t -get_ioapic_base(uint8_t apic_id) -{ - /* the ioapic base should be extracted from ACPI MADT table */ - return ioapic_array[apic_id].addr; -} - -void ioapic_get_rte_entry(void *ioapic_base, uint32_t pin, union ioapic_rte *rte) -{ - uint32_t rte_addr = (pin * 2U) + 0x10U; - rte->u.lo_32 = ioapic_read_reg32(ioapic_base, rte_addr); - rte->u.hi_32 = ioapic_read_reg32(ioapic_base, rte_addr + 1U); -} - -static inline void -ioapic_set_rte_entry(void *ioapic_base, +static void ioapic_set_rte_entry(void *ioapic_base, uint32_t pin, union ioapic_rte rte) { uint32_t rte_addr = (pin * 2U) + 0x10U; @@ -232,7 +227,7 @@ static void ioapic_set_routing(uint32_t gsi, uint32_t vr) set_irq_trigger_mode(gsi, false); } - dev_dbg(DBG_LEVEL_IRQ, "GSI: irq:%d pin:%hhu rte:%lx", + dev_dbg(DBG_LEVEL_IOAPIC, "GSI: irq:%d pin:%hhu rte:%lx", gsi, gsi_table_data[gsi].ioapic_info.pin, rte.full); } @@ -259,7 +254,13 @@ void ioapic_set_rte(uint32_t irq, union ioapic_rte rte) addr = gsi_to_ioapic_base(irq); ioapic_set_rte_entry(addr, gsi_table_data[irq].ioapic_info.pin, rte); - dev_dbg(DBG_LEVEL_IRQ, "GSI: irq:%d pin:%hhu rte:%lx", + if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) { + set_irq_trigger_mode(irq, true); + } else { + set_irq_trigger_mode(irq, false); + } + + dev_dbg(DBG_LEVEL_IOAPIC, "GSI: irq:%d pin:%hhu rte:%lx", irq, gsi_table_data[irq].ioapic_info.pin, rte.full); } @@ -288,7 +289,7 @@ bool is_ioapic_irq(uint32_t irq) /* *@pre gsi < NR_MAX_GSI - *@pre is_gsi_valid(gsi) == true + *@pre is_gsi_valid(gsi) == true */ uint32_t gsi_to_ioapic_pin(uint32_t gsi) @@ -322,10 +323,10 @@ ioapic_irq_gsi_mask_unmask(uint32_t irq, bool mask) rte.bits.intr_mask = IOAPIC_RTE_MASK_CLR; } ioapic_set_rte_entry(addr, pin, rte); - dev_dbg(DBG_LEVEL_PTIRQ, "update: irq:%d pin:%hhu rte:%lx", + dev_dbg(DBG_LEVEL_IOAPIC, "update: irq:%d pin:%hhu rte:%lx", irq, pin, rte.full); } else { - dev_dbg(DBG_LEVEL_PTIRQ, "NULL Address returned from gsi_table_data"); + dev_dbg(DBG_LEVEL_IOAPIC, "NULL Address returned from gsi_table_data"); } } @@ -339,6 +340,91 @@ void ioapic_gsi_unmask_irq(uint32_t irq) ioapic_irq_gsi_mask_unmask(irq, false); } +/* + * @pre is_ioapic_irq(irq) == true + */ +uint8_t ioapic_irq_to_ioapic_id(uint32_t irq) +{ + + return gsi_table_data[irq].ioapic_info.acpi_id; +} + +static void *map_ioapic(uint64_t ioapic_paddr) +{ + /* At some point we may need to translate this paddr to a vaddr. + * 1:1 mapping for now. + */ + return hpa2hva(ioapic_paddr); +} + +void ioapic_setup_irqs(void) +{ + uint8_t ioapic_id; + uint32_t gsi = 0U; + uint32_t vr; + + for (ioapic_id = 0U; + ioapic_id < ioapic_num; ioapic_id++) { + void *addr; + uint32_t pin, nr_pins; + + addr = map_ioapic(ioapic_array[ioapic_id].addr); + + nr_pins = ioapic_array[ioapic_id].nr_pins; + gsi = ioapic_array[ioapic_id].gsi_base; + for (pin = 0U; pin < nr_pins; pin++) { + gsi_table_data[gsi].is_valid = true; + gsi_table_data[gsi].ioapic_info.acpi_id = ioapic_array[ioapic_id].id; + gsi_table_data[gsi].ioapic_info.base_addr = addr; + gsi_table_data[gsi].ioapic_info.pin = pin; + gsi_table_data[gsi].ioapic_info.index = ioapic_id; + + /* pinned irq before use it */ + if (reserve_irq_num(gsi) == IRQ_INVALID) { + pr_err("failed to alloc IRQ[%d]", gsi); + gsi++; + continue; + } + + /* assign vector for this GSI + * for legacy irq, reserved vector and never free + */ + if (gsi < NR_LEGACY_PIN) { + vr = alloc_irq_vector(gsi); + if (vr == VECTOR_INVALID) { + pr_err("failed to alloc VR"); + gsi++; + continue; + } + } else { + vr = 0U; /* not to allocate VR right now */ + } + + ioapic_set_routing(gsi, vr); + gsi++; + } + } + + /* system max gsi numbers */ + ioapic_max_nr_gsi = gsi; +} + +uint8_t get_platform_ioapic_info (struct ioapic_info **plat_ioapic_info) +{ + *plat_ioapic_info = ioapic_array; + return ioapic_num; +} + +/** + * @pre apic_id < 2 + */ +static inline uint64_t +get_ioapic_base(uint8_t apic_id) +{ + /* the ioapic base should be extracted from ACPI MADT table */ + return ioapic_array[apic_id].addr; +} + static uint32_t ioapic_nr_pins(void *ioapic_base) { @@ -346,7 +432,7 @@ ioapic_nr_pins(void *ioapic_base) uint32_t nr_pins; version = ioapic_read_reg32(ioapic_base, IOAPIC_VER); - dev_dbg(DBG_LEVEL_IRQ, "IOAPIC version: %x", version); + dev_dbg(DBG_LEVEL_IOAPIC, "IOAPIC version: %x", version); /* The 23:16 bits in the version register is the highest entry in the * I/O redirection table, which is 1 smaller than the number of @@ -357,13 +443,11 @@ ioapic_nr_pins(void *ioapic_base) return nr_pins; } -/* - * @pre is_ioapic_irq(irq) == true - */ -uint8_t ioapic_irq_to_ioapic_id(uint32_t irq) +void ioapic_get_rte_entry(void *ioapic_base, uint32_t pin, union ioapic_rte *rte) { - - return gsi_table_data[irq].ioapic_info.acpi_id; + uint32_t rte_addr = (pin * 2U) + 0x10U; + rte->u.lo_32 = ioapic_read_reg32(ioapic_base, rte_addr); + rte->u.hi_32 = ioapic_read_reg32(ioapic_base, rte_addr + 1U); } int32_t init_ioapic_id_info(void) @@ -419,11 +503,15 @@ int32_t init_ioapic_id_info(void) return ret; } -void ioapic_setup_irqs(void) +void init_ioapic(void) { uint8_t ioapic_id; - uint32_t gsi = 0U; - uint32_t vr; + union ioapic_rte rte; + + rte.full = 0UL; + rte.bits.intr_mask = IOAPIC_RTE_MASK_SET; + + spinlock_init(&ioapic_lock); for (ioapic_id = 0U; ioapic_id < ioapic_num; ioapic_id++) { @@ -433,42 +521,10 @@ void ioapic_setup_irqs(void) addr = map_ioapic(ioapic_array[ioapic_id].addr); nr_pins = ioapic_array[ioapic_id].nr_pins; - gsi = ioapic_array[ioapic_id].gsi_base; for (pin = 0U; pin < nr_pins; pin++) { - gsi_table_data[gsi].is_valid = true; - gsi_table_data[gsi].ioapic_info.acpi_id = ioapic_array[ioapic_id].id; - gsi_table_data[gsi].ioapic_info.base_addr = addr; - gsi_table_data[gsi].ioapic_info.pin = pin; - gsi_table_data[gsi].ioapic_info.index = ioapic_id; - - /* pinned irq before use it */ - if (alloc_irq_num(gsi) == IRQ_INVALID) { - pr_err("failed to alloc IRQ[%d]", gsi); - gsi++; - continue; - } - - /* assign vector for this GSI - * for legacy irq, reserved vector and never free - */ - if (gsi < NR_LEGACY_PIN) { - vr = alloc_irq_vector(gsi); - if (vr == VECTOR_INVALID) { - pr_err("failed to alloc VR"); - gsi++; - continue; - } - } else { - vr = 0U; /* not to allocate VR right now */ - } - - ioapic_set_routing(gsi, vr); - gsi++; + ioapic_set_rte_entry(addr, pin, rte); } } - - /* system max gsi numbers */ - ioapic_max_nr_gsi = gsi; } void suspend_ioapic(void) diff --git a/hypervisor/arch/x86/irq.c b/hypervisor/arch/x86/irq.c index da4591fe50..2e1f2f8742 100644 --- a/hypervisor/arch/x86/irq.c +++ b/hypervisor/arch/x86/irq.c @@ -5,92 +5,45 @@ */ #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include -#include +#include -static spinlock_t irq_alloc_spinlock = { .head = 0U, .tail = 0U, }; +#define DBG_LEVEL_X86_IRQ 6U -uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE]; -struct irq_desc irq_desc_array[NR_IRQS]; -static uint32_t vector_to_irq[NR_MAX_VECTOR + 1]; +static spinlock_t x86_irq_spinlock = { .head = 0U, .tail = 0U, }; + +typedef void (*spurious_handler_t)(uint32_t vector); spurious_handler_t spurious_handler; -struct static_mapping_table { +static uint32_t vector_to_irq[NR_MAX_VECTOR + 1]; + +static struct x86_irq_data irq_data[NR_IRQS]; + +static struct { uint32_t irq; uint32_t vector; -}; - -static struct static_mapping_table irq_static_mappings[NR_STATIC_MAPPINGS] = { - {TIMER_IRQ, TIMER_VECTOR}, - {NOTIFY_VCPU_IRQ, NOTIFY_VCPU_VECTOR}, - {PMI_IRQ, PMI_VECTOR}, +} irq_static_mappings[NR_STATIC_MAPPINGS] = { + { TIMER_IRQ, TIMER_VECTOR }, + { NOTIFY_VCPU_IRQ, NOTIFY_VCPU_VECTOR }, + { PMI_IRQ, PMI_VECTOR }, /* To be initialized at runtime in init_irq_descs() */ - [NR_STATIC_MAPPINGS_1 ... (NR_STATIC_MAPPINGS_1 + CONFIG_MAX_VM_NUM - 1U)] = {}, + [ NR_STATIC_MAPPINGS_1 ... (NR_STATIC_MAPPINGS - 1U) ] = {}, }; -/* - * alloc an free irq if req_irq is IRQ_INVALID, or else set assigned - * return: irq num on success, IRQ_INVALID on failure - */ -uint32_t alloc_irq_num(uint32_t req_irq) -{ - uint32_t irq = req_irq; - uint64_t rflags; - uint32_t ret; - - if ((irq >= NR_IRQS) && (irq != IRQ_INVALID)) { - pr_err("[%s] invalid req_irq %u", __func__, req_irq); - ret = IRQ_INVALID; - } else { - spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); - if (irq == IRQ_INVALID) { - /* if no valid irq num given, find a free one */ - irq = (uint32_t)ffz64_ex(irq_alloc_bitmap, NR_IRQS); - } - - if (irq >= NR_IRQS) { - irq = IRQ_INVALID; - } else { - bitmap_set_nolock((uint16_t)(irq & 0x3FU), - irq_alloc_bitmap + (irq >> 6U)); - } - spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); - ret = irq; - } - return ret; -} - -/* - * @pre: irq is not in irq_static_mappings - * free irq num allocated via alloc_irq_num() - */ -static void free_irq_num(uint32_t irq) -{ - uint64_t rflags; - - if (irq < NR_IRQS) { - if (!is_ioapic_irq(irq)) { - spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); - (void)bitmap_test_and_clear_nolock((uint16_t)(irq & 0x3FU), - irq_alloc_bitmap + (irq >> 6U)); - spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); - } - } -} - /* * alloc an vectror and bind it to irq * for legacy_irq (irq num < 16) and static mapped ones, do nothing @@ -99,199 +52,97 @@ static void free_irq_num(uint32_t irq) */ uint32_t alloc_irq_vector(uint32_t irq) { - uint32_t vr; - struct irq_desc *desc; + struct x86_irq_data *irqd; uint64_t rflags; - uint32_t ret; + uint32_t vr = VECTOR_INVALID; + uint32_t ret = VECTOR_INVALID; if (irq < NR_IRQS) { - desc = &irq_desc_array[irq]; + irqd = &irq_data[irq]; + spinlock_irqsave_obtain(&x86_irq_spinlock, &rflags); - if (desc->vector != VECTOR_INVALID) { - if (vector_to_irq[desc->vector] == irq) { - /* statically binded */ - vr = desc->vector; + if (irqd->vector <= NR_MAX_VECTOR) { + if (vector_to_irq[irqd->vector] == irq) { + /* statically bound */ + vr = irqd->vector; } else { pr_err("[%s] irq[%u]:vector[%u] mismatch", - __func__, irq, desc->vector); - vr = VECTOR_INVALID; + __func__, irq, irqd->vector); } } else { - /* alloc a vector between: + /* + * alloc a vector between: * VECTOR_DYNAMIC_START ~ VECTOR_DYNAMC_END */ - spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); for (vr = VECTOR_DYNAMIC_START; vr <= VECTOR_DYNAMIC_END; vr++) { if (vector_to_irq[vr] == IRQ_INVALID) { - desc->vector = vr; + irqd->vector = vr; vector_to_irq[vr] = irq; break; } } - vr = (vr > VECTOR_DYNAMIC_END) ? VECTOR_INVALID : vr; - spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); + vr = (vr > VECTOR_DYNAMIC_END) ? VECTOR_INVALID : vr; } + spinlock_irqrestore_release(&x86_irq_spinlock, rflags); ret = vr; } else { pr_err("invalid irq[%u] to alloc vector", irq); - ret = VECTOR_INVALID; } return ret; } -/* free the vector allocated via alloc_irq_vector() */ -static void free_irq_vector(uint32_t irq) +uint32_t irq_to_vector(uint32_t irq) { - struct irq_desc *desc; - uint32_t vr; uint64_t rflags; + uint32_t ret = VECTOR_INVALID; if (irq < NR_IRQS) { - desc = &irq_desc_array[irq]; - - if ((irq >= NR_LEGACY_IRQ) && (desc->vector < VECTOR_FIXED_START)) { - /* do nothing for LEGACY_IRQ and static allocated ones */ - - spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); - vr = desc->vector; - desc->vector = VECTOR_INVALID; - - vr &= NR_MAX_VECTOR; - if (vector_to_irq[vr] == irq) { - vector_to_irq[vr] = IRQ_INVALID; - } - spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); - } - } -} - -/* - * There are four cases as to irq/vector allocation: - * case 1: req_irq = IRQ_INVALID - * caller did not know which irq to use, and want system to - * allocate available irq for it. These irq are in range: - * nr_gsi ~ NR_IRQS - * an irq will be allocated and a vector will be assigned to this - * irq automatically. - * case 2: req_irq >= NR_LAGACY_IRQ and irq < nr_gsi - * caller want to add device ISR handler into ioapic pins. - * a vector will automatically assigned. - * case 3: req_irq >=0 and req_irq < NR_LEGACY_IRQ - * caller want to add device ISR handler into ioapic pins, which - * is a legacy irq, vector already reserved. - * Nothing to do in this case. - * case 4: irq with speical type (not from IOAPIC/MSI) - * These irq value are pre-defined for Timer, IPI, Spurious etc, - * which is listed in irq_static_mappings[]. - * Nothing to do in this case. - * - * return value: valid irq (>=0) on success, otherwise errno (< 0). - */ -int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, - uint32_t flags) -{ - struct irq_desc *desc; - uint32_t irq, vector; - uint64_t rflags; - int32_t ret; - - irq = alloc_irq_num(req_irq); - if (irq == IRQ_INVALID) { - pr_err("[%s] invalid irq num", __func__); - ret = -EINVAL; - } else { - vector = alloc_irq_vector(irq); - - if (vector == VECTOR_INVALID) { - pr_err("[%s] failed to alloc vector for irq %u", - __func__, irq); - free_irq_num(irq); - ret = -EINVAL; - } else { - desc = &irq_desc_array[irq]; - if (desc->action == NULL) { - spinlock_irqsave_obtain(&desc->lock, &rflags); - desc->flags = flags; - desc->priv_data = priv_data; - desc->action = action_fn; - spinlock_irqrestore_release(&desc->lock, rflags); - - ret = (int32_t)irq; - dev_dbg(DBG_LEVEL_IRQ, "[%s] irq%d vr:0x%x", __func__, irq, desc->vector); - } else { - ret = -EBUSY; - pr_err("%s: request irq(%u) vr(%u) failed, already requested", __func__, - irq, irq_to_vector(irq)); - } - } + spinlock_irqsave_obtain(&x86_irq_spinlock, &rflags); + ret = irq_data[irq].vector; + spinlock_irqrestore_release(&x86_irq_spinlock, rflags); } return ret; } -void free_irq(uint32_t irq) +bool request_irq_arch(uint32_t irq) { - uint64_t rflags; - struct irq_desc *desc; - - if (irq < NR_IRQS) { - desc = &irq_desc_array[irq]; - dev_dbg(DBG_LEVEL_IRQ, "[%s] irq%d vr:0x%x", - __func__, irq, irq_to_vector(irq)); - - free_irq_vector(irq); - free_irq_num(irq); - - spinlock_irqsave_obtain(&desc->lock, &rflags); - desc->action = NULL; - desc->priv_data = NULL; - desc->flags = IRQF_NONE; - spinlock_irqrestore_release(&desc->lock, rflags); - } + return (alloc_irq_vector(irq) != VECTOR_INVALID); } -void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered) +/* free the vector allocated via alloc_irq_vector() */ +static void free_irq_vector(uint32_t irq) { + struct x86_irq_data *irqd; + uint32_t vr; uint64_t rflags; - struct irq_desc *desc; - if (irq < NR_IRQS) { - desc = &irq_desc_array[irq]; - spinlock_irqsave_obtain(&desc->lock, &rflags); - if (is_level_triggered) { - desc->flags |= IRQF_LEVEL; - } else { - desc->flags &= ~IRQF_LEVEL; + if ((irq >= NR_LEGACY_IRQ) && (irq < NR_IRQS)) { + irqd = &irq_data[irq]; + spinlock_irqsave_obtain(&x86_irq_spinlock, &rflags); + + if (irqd->vector < VECTOR_FIXED_START) { + /* do nothing for LEGACY_IRQ and statically allocated ones */ + vr = irqd->vector; + irqd->vector = VECTOR_INVALID; + + if (vr <= NR_MAX_VECTOR && vector_to_irq[vr] == irq) { + vector_to_irq[vr] = IRQ_INVALID; + } } - spinlock_irqrestore_release(&desc->lock, rflags); + spinlock_irqrestore_release(&x86_irq_spinlock, rflags); } } -uint32_t irq_to_vector(uint32_t irq) +void free_irq_arch(uint32_t irq) { - uint32_t ret; if (irq < NR_IRQS) { - ret = irq_desc_array[irq].vector; - } else { - ret = VECTOR_INVALID; - } - - return ret; -} - -static void handle_spurious_interrupt(uint32_t vector) -{ - send_lapic_eoi(); - - get_cpu_var(spurious)++; - - pr_warn("Spurious vector: 0x%x.", vector); - - if (spurious_handler != NULL) { - spurious_handler(vector); + dev_dbg(DBG_LEVEL_X86_IRQ, "[%s] irq%d vr:0x%x", + __func__, irq, irq_to_vector(irq)); + free_irq_vector(irq); } } @@ -310,106 +161,94 @@ static inline bool irq_need_unmask(const struct irq_desc *desc) && is_ioapic_irq(desc->irq)); } -static inline void handle_irq(const struct irq_desc *desc) +void pre_irq_arch(const struct irq_desc *desc) { - irq_action_t action = desc->action; - if (irq_need_mask(desc)) { ioapic_gsi_mask_irq(desc->irq); } +} +void eoi_irq_arch(__unused const struct irq_desc *desc) +{ /* Send EOI to LAPIC/IOAPIC IRR */ send_lapic_eoi(); +} - if (action != NULL) { - action(desc->irq, desc->priv_data); - } - +void post_irq_arch(const struct irq_desc *desc) +{ if (irq_need_unmask(desc)) { ioapic_gsi_unmask_irq(desc->irq); } } -/* do_IRQ() */ +static void handle_spurious_interrupt(uint32_t vector) +{ + send_lapic_eoi(); + + get_cpu_var(spurious)++; + + pr_warn("Spurious vector: 0x%x.", vector); + + if (spurious_handler != NULL) { + spurious_handler(vector); + } +} + void dispatch_interrupt(const struct intr_excp_ctx *ctx) { uint32_t vr = ctx->vector; uint32_t irq = vector_to_irq[vr]; - struct irq_desc *desc; + struct x86_irq_data *irqd; - /* The value from vector_to_irq[] must be: + /* + * The value from vector_to_irq[] must be: + * * IRQ_INVALID, which means the vector is not allocated; * or - * < NR_IRQS, which is the irq number it bound with; + * < NR_IRQS, which is the irq number it's bound to; * Any other value means there is something wrong. */ if (irq < NR_IRQS) { - desc = &irq_desc_array[irq]; - per_cpu(irq_count, get_pcpu_id())[irq]++; + irqd = &irq_data[irq]; - if ((vr == desc->vector) && - bitmap_test((uint16_t)(irq & 0x3FU), irq_alloc_bitmap + (irq >> 6U))) { + if (vr == irqd->vector) { #ifdef PROFILING_ON - /* Saves ctx info into irq_desc */ - desc->ctx_rip = ctx->rip; - desc->ctx_rflags = ctx->rflags; - desc->ctx_cs = ctx->cs; + /* Save ctx info into irq_data */ + irqd->ctx_rip = ctx->rip; + irqd->ctx_rflags = ctx->rflags; + irqd->ctx_cs = ctx->cs; #endif - handle_irq(desc); + do_irq(irq); } } else { handle_spurious_interrupt(vr); } - - do_softirq(); } -void dispatch_exception(struct intr_excp_ctx *ctx) +/* XXX lockless operation */ +bool irq_allocated_arch(struct irq_desc *desc) { - uint16_t pcpu_id = get_pcpu_id(); - - /* Dump exception context */ - dump_exception(ctx, pcpu_id); + struct x86_irq_data *irqd = NULL; + uint32_t irq = IRQ_INVALID; + uint32_t vr = VECTOR_INVALID; - /* Halt the CPU */ - cpu_dead(); -} + if (desc != NULL) { + irq = desc->irq; + irqd = desc->arch_data; + } -void handle_nmi(__unused struct intr_excp_ctx *ctx) -{ - uint32_t value32; + if (irqd != NULL) { + vr = irqd->vector; + } - /* - * There is a window where we may miss the current request in this - * notification period when the work flow is as the following: - * - * CPUx + + CPUr - * | | - * | +--+ - * | | | Handle pending req - * | <--+ - * +--+ | - * | | Set req flag | - * <--+ | - * +------------------>---+ - * | Send NMI | | Handle NMI - * | <--+ - * | | - * | | - * | +--> vCPU enter - * | | - * + + - * - * So, here we enable the NMI-window exiting to trigger the next vmexit - * once there is no "virtual-NMI blocking" after vCPU enter into VMX non-root - * mode. Then we can process the pending request on time. - */ - value32 = exec_vmread32(VMX_PROC_VM_EXEC_CONTROLS); - value32 |= VMX_PROCBASED_CTLS_NMI_WINEXIT; - exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS, value32); + return ((irq < NR_IRQS) && (vr <= NR_MAX_VECTOR) && + (vector_to_irq[vr] == irq)); } -static void init_irq_descs(void) +/* + * descs[] must have NR_IRQS entries + */ +void init_irq_descs_arch(struct irq_desc descs[]) { uint32_t i; @@ -428,43 +267,34 @@ static void init_irq_descs(void) } for (i = 0U; i < NR_IRQS; i++) { - irq_desc_array[i].irq = i; - irq_desc_array[i].vector = VECTOR_INVALID; - spinlock_init(&irq_desc_array[i].lock); + irq_data[i].vector = VECTOR_INVALID; + descs[i].arch_data = &irq_data[i]; } - for (i = 0U; i <= NR_MAX_VECTOR; i++) { + for (i = 0U; i < ARRAY_SIZE(vector_to_irq); i++) { vector_to_irq[i] = IRQ_INVALID; } /* init fixed mapping for specific irq and vector */ - for (i = 0U; i < NR_STATIC_MAPPINGS; i++) { + for (i = 0U; i < ARRAY_SIZE(irq_static_mappings); i++) { uint32_t irq = irq_static_mappings[i].irq; uint32_t vr = irq_static_mappings[i].vector; - irq_desc_array[irq].vector = vr; + /* XXX irq0 -> vec0 ? */ + irq_data[irq].vector = vr; vector_to_irq[vr] = irq; - bitmap_set_nolock((uint16_t)(irq & 0x3FU), - irq_alloc_bitmap + (irq >> 6U)); } } -static void disable_pic_irqs(void) +void setup_irqs_arch(void) { - pio_write8(0xffU, 0xA1U); - pio_write8(0xffU, 0x21U); + ioapic_setup_irqs(); } -void init_default_irqs(uint16_t cpu_id) +static void disable_pic_irqs(void) { - if (cpu_id == BSP_CPU_ID) { - init_irq_descs(); - - /* we use ioapic only, disable legacy PIC */ - disable_pic_irqs(); - ioapic_setup_irqs(); - init_softirq(); - } + pio_write8(0xffU, 0xA1U); + pio_write8(0xffU, 0x21U); } static inline void fixup_idt(const struct host_idt_descriptor *idtd) @@ -490,7 +320,7 @@ static inline void set_idt(struct host_idt_descriptor *idtd) [idtd] "m"(*idtd)); } -void init_interrupt(uint16_t pcpu_id) +void init_interrupt_arch(uint16_t pcpu_id) { struct host_idt_descriptor *idtd = &HOST_IDTR; @@ -499,7 +329,10 @@ void init_interrupt(uint16_t pcpu_id) } set_idt(idtd); init_lapic(pcpu_id); - init_default_irqs(pcpu_id); - CPU_IRQ_ENABLE(); + if (pcpu_id == BSP_CPU_ID) { + /* we use ioapic only, disable legacy PIC */ + disable_pic_irqs(); + init_ioapic(); + } } diff --git a/hypervisor/arch/x86/lapic.c b/hypervisor/arch/x86/lapic.c index 2ff017ea69..03cfd67ae8 100644 --- a/hypervisor/arch/x86/lapic.c +++ b/hypervisor/arch/x86/lapic.c @@ -5,12 +5,40 @@ */ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* intr_lapic_icr_delivery_mode */ +#define INTR_LAPIC_ICR_FIXED 0x0U +#define INTR_LAPIC_ICR_LP 0x1U +#define INTR_LAPIC_ICR_SMI 0x2U +#define INTR_LAPIC_ICR_NMI 0x4U +#define INTR_LAPIC_ICR_INIT 0x5U +#define INTR_LAPIC_ICR_STARTUP 0x6U + +/* intr_lapic_icr_dest_mode */ +#define INTR_LAPIC_ICR_PHYSICAL 0x0U +#define INTR_LAPIC_ICR_LOGICAL 0x1U + +/* intr_lapic_icr_level */ +#define INTR_LAPIC_ICR_DEASSERT 0x0U +#define INTR_LAPIC_ICR_ASSERT 0x1U + +/* intr_lapic_icr_trigger */ +#define INTR_LAPIC_ICR_EDGE 0x0U +#define INTR_LAPIC_ICR_LEVEL 0x1U + +/* intr_lapic_icr_shorthand */ +#define INTR_LAPIC_ICR_USE_DEST_ARRAY 0x0U +#define INTR_LAPIC_ICR_SELF 0x1U +#define INTR_LAPIC_ICR_ALL_INC_SELF 0x2U +#define INTR_LAPIC_ICR_ALL_EX_SELF 0x3U union lapic_base_msr { uint64_t value; @@ -171,7 +199,6 @@ void send_startup_ipi(uint16_t dest_pcpu_id, uint64_t cpu_startup_start_address) { union apic_icr icr; - struct cpuinfo_x86 *cpu_info = get_pcpu_info(); icr.value = 0U; icr.value_32.hi_32 = per_cpu(lapic_id, dest_pcpu_id); @@ -187,7 +214,7 @@ send_startup_ipi(uint16_t dest_pcpu_id, uint64_t cpu_startup_start_address) * and first Startup IPI, so on Modern processors (family == 6) * setting a delay value of 10us. */ - if (cpu_info->displayfamily != 6U) { + if (pcpu_family_id() != 6U) { /* delay 10ms */ udelay(10000U); } else { @@ -201,7 +228,7 @@ send_startup_ipi(uint16_t dest_pcpu_id, uint64_t cpu_startup_start_address) icr.bits.vector = (uint8_t)(cpu_startup_start_address >> 12U); msr_write(MSR_IA32_EXT_APIC_ICR, icr.value); - if (cpu_info->displayfamily == 6U) { + if (pcpu_family_id() == 6U) { udelay(10U); /* 10us is enough for Modern processors */ } else { udelay(200U); /* 200us for old processors */ diff --git a/hypervisor/arch/x86/mmu.c b/hypervisor/arch/x86/mmu.c index 439ee0cd6b..d0b6e4a780 100644 --- a/hypervisor/arch/x86/mmu.c +++ b/hypervisor/arch/x86/mmu.c @@ -28,15 +28,15 @@ */ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include +#include +#include #include #include diff --git a/hypervisor/arch/x86/nmi.c b/hypervisor/arch/x86/nmi.c new file mode 100644 index 0000000000..b9ef477616 --- /dev/null +++ b/hypervisor/arch/x86/nmi.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +void handle_nmi(__unused struct intr_excp_ctx *ctx) +{ + uint32_t value32; + + /* + * There is a window where we may miss the current request in this + * notification period when the work flow is as the following: + * + * CPUx + + CPUr + * | | + * | +--+ + * | | | Handle pending req + * | <--+ + * +--+ | + * | | Set req flag | + * <--+ | + * +------------------>---+ + * | Send NMI | | Handle NMI + * | <--+ + * | | + * | | + * | +--> vCPU enter + * | | + * + + + * + * So, here we enable the NMI-window exiting to trigger the next vmexit + * once there is no "virtual-NMI blocking" after vCPU enter into VMX non-root + * mode. Then we can process the pending request on time. + */ + value32 = exec_vmread32(VMX_PROC_VM_EXEC_CONTROLS); + value32 |= VMX_PROCBASED_CTLS_NMI_WINEXIT; + exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS, value32); +} diff --git a/hypervisor/arch/x86/notify.c b/hypervisor/arch/x86/notify.c index f97a02e04e..9918858c64 100644 --- a/hypervisor/arch/x86/notify.c +++ b/hypervisor/arch/x86/notify.c @@ -6,13 +6,16 @@ #include #include -#include -#include +#include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include +#include + +#define DBG_LEVEL_NOTIFY 6U static uint32_t notification_irq = IRQ_INVALID; @@ -94,7 +97,7 @@ void setup_notification(void) pr_err("Failed to setup notification"); } - dev_dbg(DBG_LEVEL_PTIRQ, "NOTIFY: irq[%d] setup vector %x", + dev_dbg(DBG_LEVEL_NOTIFY, "NOTIFY: irq[%d] setup vector %x", notification_irq, irq_to_vector(notification_irq)); } diff --git a/hypervisor/arch/x86/page.c b/hypervisor/arch/x86/page.c index b94428a684..26d87abc09 100644 --- a/hypervisor/arch/x86/page.c +++ b/hypervisor/arch/x86/page.c @@ -5,14 +5,13 @@ */ #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #define LINEAR_ADDRESS_SPACE_48_BIT (1UL << 48U) diff --git a/hypervisor/arch/x86/pagetable.c b/hypervisor/arch/x86/pagetable.c index be5ffc8948..22452d7b56 100644 --- a/hypervisor/arch/x86/pagetable.c +++ b/hypervisor/arch/x86/pagetable.c @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include #include #define DBG_LEVEL_MMU 6U diff --git a/hypervisor/arch/x86/platform_caps.c b/hypervisor/arch/x86/platform_caps.c index c5321608c2..8431d9994e 100644 --- a/hypervisor/arch/x86/platform_caps.c +++ b/hypervisor/arch/x86/platform_caps.c @@ -5,6 +5,6 @@ */ #include -#include +#include struct platform_caps_x86 platform_caps = {.pi = true}; diff --git a/hypervisor/arch/x86/pm.c b/hypervisor/arch/x86/pm.c index 017be8c916..3f9cb20098 100644 --- a/hypervisor/arch/x86/pm.c +++ b/hypervisor/arch/x86/pm.c @@ -4,19 +4,21 @@ */ #include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include +#include +#include struct cpu_context cpu_ctx; @@ -163,7 +165,7 @@ void shutdown_system(void) static void suspend_tsc(__unused void *data) { - per_cpu(tsc_suspend, get_pcpu_id()) = rdtsc(); + per_cpu(tsc_suspend, get_pcpu_id()) = get_cpu_cycles(); } static void resume_tsc(__unused void *data) diff --git a/hypervisor/arch/x86/ptintr.c b/hypervisor/arch/x86/ptintr.c new file mode 100644 index 0000000000..1a79494b39 --- /dev/null +++ b/hypervisor/arch/x86/ptintr.c @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DBG_LEVEL_PTINTR 6U + +union irte_index { + uint16_t index; + struct { + uint16_t index_low:15; + uint16_t index_high:1; + } bits __packed; +}; + +static struct ptintr *(*find_intr)(uint32_t, const union source_id *, + const struct acrn_vm *); + +/* + * Check if the IRQ is single-destination and return the destination vCPU if so. + * + * VT-d PI (posted mode) cannot support multicast/broadcast IRQs. + * If returns NULL, this means it is multicast/broadcast IRQ and + * we can only handle it in remapped mode. + * If returns non-NULL, the destination vCPU is returned, which means it is + * single-destination IRQ and we can handle it in posted mode. + * + * @pre (vm != NULL) && (info != NULL) + */ +static struct acrn_vcpu *is_single_destination(struct acrn_vm *vm, const struct msi_info *info) +{ + uint64_t vdmask; + uint16_t vid; + struct acrn_vcpu *vcpu = NULL; + + vlapic_calc_dest(vm, &vdmask, false, (uint32_t)(info->addr.bits.dest_field), + (bool)(info->addr.bits.dest_mode == MSI_ADDR_DESTMODE_PHYS), + (bool)(info->data.bits.delivery_mode == MSI_DATA_DELMODE_LOPRI)); + + /* Can only post fixed and Lowpri IRQs */ + if ((info->data.bits.delivery_mode == MSI_DATA_DELMODE_FIXED) + || (info->data.bits.delivery_mode == MSI_DATA_DELMODE_LOPRI)) { + vid = ffs64(vdmask); + + /* Can only post single-destination IRQs */ + if (vdmask == (1UL << vid)) { + vcpu = vcpu_from_vid(vm, vid); + } + } + + return vcpu; +} + +static uint32_t calculate_logical_dest_mask(uint64_t pdmask) +{ + uint32_t dest_mask = 0UL; + uint64_t pcpu_mask = pdmask; + uint16_t pcpu_id; + + pcpu_id = ffs64(pcpu_mask); + while (pcpu_id < MAX_PCPU_NUM) { + bitmap_clear_nolock(pcpu_id, &pcpu_mask); + dest_mask |= per_cpu(lapic_ldr, pcpu_id); + pcpu_id = ffs64(pcpu_mask); + } + return dest_mask; +} + +/* + * pid_paddr = 0: invalid address, indicate that remapped mode shall be used + * + * pid_paddr != 0: physical address of posted interrupt descriptor, indicate + * that posted mode shall be used + */ +static void build_physical_msi(struct ptintr *intr, struct msi_info *vmsi, + uint32_t vector, uint64_t pid_paddr, uint16_t irte_idx) +{ + struct acrn_vm *vm = intr->vm; + struct msi_info *pmsi = &intr->pmsi; + uint64_t vdmask, pdmask; + uint32_t dest, delmode, dest_mask; + int32_t ret; + bool phys; + union dmar_ir_entry irte; + union irte_index ir_index; + struct intr_source intr_src; + + /* get physical destination cpu mask */ + dest = vmsi->addr.bits.dest_field; + phys = (vmsi->addr.bits.dest_mode == MSI_ADDR_DESTMODE_PHYS); + + vlapic_calc_dest(vm, &vdmask, false, dest, phys, false); + pdmask = vcpumask2pcpumask(vm, vdmask); + + /* get physical delivery mode */ + delmode = vmsi->data.bits.delivery_mode; + if ((delmode != MSI_DATA_DELMODE_FIXED) && (delmode != MSI_DATA_DELMODE_LOPRI)) { + delmode = MSI_DATA_DELMODE_LOPRI; + } + + dest_mask = calculate_logical_dest_mask(pdmask); + + irte.value.lo_64 = 0UL; + irte.value.hi_64 = 0UL; + irte.bits.remap.vector = vector; + irte.bits.remap.delivery_mode = delmode; + irte.bits.remap.dest_mode = MSI_ADDR_DESTMODE_LOGICAL; + irte.bits.remap.rh = MSI_ADDR_RH; + irte.bits.remap.dest = dest_mask; + + intr_src.is_msi = true; + intr_src.pid_paddr = pid_paddr; + intr_src.src.msi.value = intr->phys_sid.msi_id.bdf; + ret = dmar_assign_irte(&intr_src, &irte, irte_idx, &ir_index.index); + + if (ret == 0) { + /* + * Update the MSI interrupt source to point to the IRTE + * SHV is set to 0 as ACRN disables MMC (Multi-Message Capable + * for MSI devices. + */ + pmsi->data.full = 0U; + pmsi->addr.full = 0UL; + + intr->irte_idx = ir_index.index; + if (ir_index.index != INVALID_IRTE_ID) { + pmsi->addr.ir_bits.intr_index_high = ir_index.bits.index_high; + pmsi->addr.ir_bits.shv = 0U; + pmsi->addr.ir_bits.intr_format = 0x1U; + pmsi->addr.ir_bits.intr_index_low = ir_index.bits.index_low; + pmsi->addr.ir_bits.constant = 0xFEEU; + } + } else { + /* + * In case there is no corresponding IOMMU, for example, if the + * IOMMU is ignored, pass the MSI info in Compatibility Format + */ + pmsi->data = vmsi->data; + pmsi->data.bits.delivery_mode = delmode; + pmsi->data.bits.vector = vector; + + pmsi->addr = vmsi->addr; + pmsi->addr.bits.dest_field = dest_mask; + pmsi->addr.bits.rh = MSI_ADDR_RH; + pmsi->addr.bits.dest_mode = MSI_ADDR_DESTMODE_LOGICAL; + } + dev_dbg(DBG_LEVEL_PTINTR, "MSI %s addr:data = 0x%lx:%x(V) -> 0x%lx:%x(P)", + (pmsi->addr.ir_bits.intr_format != 0U) ? + "Remappable Format" : "Compatibility Format", + vmsi->addr.full, vmsi->data.full, + pmsi->addr.full, pmsi->data.full); +} + +static union ioapic_rte build_physical_rte(struct acrn_vm *vm, struct ptintr *intr) +{ + union ioapic_rte rte; + uint32_t phys_irq = ptirq_get_irq(intr->irq); + union source_id *virt_sid = &intr->virt_sid; + union irte_index ir_index; + union dmar_ir_entry irte; + struct intr_source intr_src; + int32_t ret; + + if (virt_sid->intx_id.ctlr == INTX_CTLR_IOAPIC) { + uint64_t vdmask, pdmask; + uint32_t dest, delmode, dest_mask, vector; + union ioapic_rte virt_rte; + bool phys; + + vioapic_get_rte(vm, virt_sid->intx_id.gsi, &virt_rte); + rte = virt_rte; + + /* init polarity & pin state */ + if (rte.bits.intr_polarity == IOAPIC_RTE_INTPOL_ALO) { + if (ptirq_get_polarity(intr->irq) == 0U) { + vioapic_set_irqline_nolock(vm, virt_sid->intx_id.gsi, GSI_SET_HIGH); + } + ptirq_set_polarity(intr->irq, 1U); + } else { + if (ptirq_get_polarity(intr->irq) == 1U) { + vioapic_set_irqline_nolock(vm, virt_sid->intx_id.gsi, GSI_SET_LOW); + } + ptirq_set_polarity(intr->irq, 0U); + } + + /* physical destination cpu mask */ + phys = (virt_rte.bits.dest_mode == IOAPIC_RTE_DESTMODE_PHY); + dest = (uint32_t)virt_rte.bits.dest_field; + vlapic_calc_dest(vm, &vdmask, false, dest, phys, false); + pdmask = vcpumask2pcpumask(vm, vdmask); + + /* physical delivery mode */ + delmode = virt_rte.bits.delivery_mode; + if ((delmode != IOAPIC_RTE_DELMODE_FIXED) && + (delmode != IOAPIC_RTE_DELMODE_LOPRI)) { + delmode = IOAPIC_RTE_DELMODE_LOPRI; + } + + /* update physical delivery mode, dest mode(logical) & vector */ + vector = irq_to_vector(phys_irq); + dest_mask = calculate_logical_dest_mask(pdmask); + + irte.value.lo_64 = 0UL; + irte.value.hi_64 = 0UL; + irte.bits.remap.vector = vector; + irte.bits.remap.delivery_mode = delmode; + irte.bits.remap.dest_mode = IOAPIC_RTE_DESTMODE_LOGICAL; + irte.bits.remap.dest = dest_mask; + irte.bits.remap.trigger_mode = rte.bits.trigger_mode; + + intr_src.is_msi = false; + intr_src.pid_paddr = 0UL; + intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq); + ret = dmar_assign_irte(&intr_src, &irte, INVALID_IRTE_ID, &ir_index.index); + + if (ret == 0) { + intr->irte_idx = ir_index.index; + if (ir_index.index != INVALID_IRTE_ID) { + rte.ir_bits.vector = vector; + rte.ir_bits.constant = 0U; + rte.ir_bits.intr_index_high = ir_index.bits.index_high; + rte.ir_bits.intr_format = 1U; + rte.ir_bits.intr_index_low = ir_index.bits.index_low; + } else { + rte.bits.intr_mask = 1; + } + } else { + rte.bits.dest_mode = IOAPIC_RTE_DESTMODE_LOGICAL; + rte.bits.delivery_mode = delmode; + rte.bits.vector = vector; + rte.bits.dest_field = dest_mask; + } + + dev_dbg(DBG_LEVEL_PTINTR, "IOAPIC RTE %s = 0x%x:%x(V) -> 0x%x:%x(P)", + (rte.ir_bits.intr_format != 0U) ? "Remappable Format" : "Compatibility Format", + virt_rte.u.hi_32, virt_rte.u.lo_32, + rte.u.hi_32, rte.u.lo_32); + } else { + enum vpic_trigger trigger; + union ioapic_rte phys_rte; + + /* just update trigger mode */ + ioapic_get_rte(phys_irq, &phys_rte); + rte = phys_rte; + rte.bits.trigger_mode = IOAPIC_RTE_TRGRMODE_EDGE; + vpic_get_irqline_trigger_mode(vm_pic(vm), (uint32_t)virt_sid->intx_id.gsi, &trigger); + if (trigger == LEVEL_TRIGGER) { + rte.bits.trigger_mode = IOAPIC_RTE_TRGRMODE_LEVEL; + } + + dev_dbg(DBG_LEVEL_PTINTR, "IOAPIC RTE %s = 0x%x:%x(P) -> 0x%x:%x(P)", + (rte.ir_bits.intr_format != 0U) ? "Remappable Format" : "Compatibility Format", + phys_rte.u.hi_32, phys_rte.u.lo_32, + rte.u.hi_32, rte.u.lo_32); + } + + return rte; +} + +int32_t ptintr_add_intx_arch(struct acrn_vm *vm, union source_id *virt_sid) +{ + int32_t ret = -ENODEV; + struct ptintr *intr = NULL; + uint32_t virt_gsi = virt_sid->intx_id.gsi; + enum intx_ctlr virt_ctlr = virt_sid->intx_id.ctlr; + DEFINE_INTX_SID(alt_virt_sid, virt_gsi, virt_ctlr); + + /* + * virt pin could come from vpic master, vpic slave or vioapic + * while phys pin is always means for physical IOAPIC. + * + * For SOS(sos_vm), it adds the mapping entries at runtime, if the + * entry already be held by others, return error. + */ + if (is_sos_vm(vm) && (virt_gsi < NR_LEGACY_PIN)) { + /* + * For sos_vm, there is chance of vpin source switch + * between vPIC & vIOAPIC for one legacy phys_pin. + * + * Here we check if there is already a mapping entry + * from the other vpin source for a legacy pin. If + * yes, then switching the vpin source is needed. + */ + alt_virt_sid.intx_id.ctlr = (virt_ctlr == INTX_CTLR_PIC) ? + INTX_CTLR_IOAPIC : INTX_CTLR_PIC; + + intr = find_intr(PTDEV_INTR_INTX, &alt_virt_sid, vm); + + if (intr != NULL) { + intr->virt_sid = *virt_sid; + /* FIXME re-insert */ + ret = -EACCES; + dev_dbg(DBG_LEVEL_PTINTR, + "IOAPIC gsi=%hhu pirq=%u vgsi=%d switch from %s to %s for vm%d", + intr->phys_sid.intx_id.gsi, + ptirq_get_irq(intr->irq), intr->virt_sid.intx_id.gsi, + (virt_ctlr == INTX_CTLR_IOAPIC) ? "vPIC" : "vIOAPIC", + (virt_ctlr == INTX_CTLR_IOAPIC) ? "vIOPIC" : "vPIC", + intr->vm->vm_id); + } + } + + return ret; +} + +/* + * Main entry for PCI device assignment with MSI and MSI-X + * MSI can up to 8 vectors and MSI-X can up to 1024 Vectors + * We use entry_nr to indicate coming vectors + * entry_nr = 0 means first vector + * user must provide bdf and entry_nr + */ +int32_t ptintr_remap_msix_arch(struct ptintr *intr, struct ptintr_remap_msix *args) +{ + struct acrn_vm *vm = intr->vm; + struct msi_info *vmsi = args->info; + union pci_bdf vbdf; + bool is_ptirq = false; + uint32_t ptirq_vr = 0; + uint16_t irte_idx = args->irte_idx; + int32_t ret = 0; + + /* build physical config MSI, update to intr->pmsi */ + if (is_lapic_pt_configured(vm)) { + enum vm_vlapic_mode vlapic_mode = check_vm_vlapic_mode(vm); + + if (vlapic_mode == VM_VLAPIC_X2APIC) { + /* + * All the vCPUs are in x2APIC mode and LAPIC is Pass-through + * Use guest vector to program the interrupt source + */ + build_physical_msi(intr, vmsi, + (uint32_t)vmsi->data.bits.vector, 0UL, irte_idx); + } else if (vlapic_mode == VM_VLAPIC_XAPIC) { + /* + * All the vCPUs are in xAPIC mode and LAPIC is emulated + * Use host vector to program the interrupt source + */ + is_ptirq = true; + ptirq_vr = irq_to_vector(ptirq_get_irq(intr->irq)); + build_physical_msi(intr, vmsi, ptirq_vr, 0UL, irte_idx); + } else if (vlapic_mode == VM_VLAPIC_TRANSITION) { + /* + * vCPUs are in middle of transition, so do not program interrupt source + * TODO: Devices programmed during transistion do not work after transition + * as device is not programmed with interrupt info. Need to implement a + * method to get interrupts working after transition. + */ + ret = -EFAULT; + } else { + /* Do nothing for VM_VLAPIC_DISABLED */ + ret = -EFAULT; + } + } else { + struct acrn_vcpu *vcpu = is_single_destination(vm, vmsi); + + if (is_pi_capable(vm) && (vcpu != NULL)) { + build_physical_msi(intr, vmsi, + (uint32_t)vmsi->data.bits.vector, + hva2hpa(get_pi_desc(vcpu)), irte_idx); + } else { + /* + * Go with remapped mode if we cannot handle it in posted mode + */ + is_ptirq = true; + ptirq_vr = irq_to_vector(ptirq_get_irq(intr->irq)); + build_physical_msi(intr, vmsi, ptirq_vr, 0UL, irte_idx); + } + } + + if (ret == 0) { + vbdf.value = intr->virt_sid.msi_id.bdf; + dev_dbg(DBG_LEVEL_PTINTR, "PCI %x:%x.%x MSI VR[%d] 0x%x->0x%x assigned to vm%u", + vbdf.bits.b, vbdf.bits.d, vbdf.bits.f, intr->virt_sid.msi_id.entry_nr, + vmsi->data.bits.vector, + is_ptirq ? ptirq_vr : (uint32_t)vmsi->data.bits.vector, + vm->vm_id); + } + + return ret; +} + +static void activate_physical_ioapic(struct ptintr *intr) +{ + struct acrn_vm *vm = intr->vm; + union ioapic_rte rte; + uint32_t phys_irq = ptirq_get_irq(intr->irq); + uint64_t intr_mask; + bool is_lvl_trigger = false; + + /* disable interrupt */ + ioapic_gsi_mask_irq(phys_irq); + + /* build physical IOAPIC RTE */ + rte = build_physical_rte(vm, intr); + intr_mask = rte.bits.intr_mask; + + /* update irq trigger mode according to info in guest */ + if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) { + is_lvl_trigger = true; + } + set_irq_trigger_mode(phys_irq, is_lvl_trigger); + + /* set rte entry when masked */ + rte.bits.intr_mask = IOAPIC_RTE_MASK_SET; + ioapic_set_rte(phys_irq, rte); + + if (intr_mask == IOAPIC_RTE_MASK_CLR) { + ioapic_gsi_unmask_irq(phys_irq); + } +} + +int32_t ptintr_remap_intx_arch(struct ptintr *intr, __unused struct ptintr_remap_intx *args) +{ + activate_physical_ioapic(intr); + return 0; +} + +static void remove_remapping(const struct ptintr *intr) +{ + uint32_t phys_irq = ptirq_get_irq(intr->irq); + struct intr_source intr_src; + + if (intr->intr_type == PTDEV_INTR_MSI) { + intr_src.is_msi = true; + intr_src.src.msi.value = intr->phys_sid.msi_id.bdf; + } else { + intr_src.is_msi = false; + intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq); + } + + dmar_free_irte(&intr_src, intr->irte_idx); +} + +void ptintr_remove_msix_arch(struct ptintr *intr) +{ + remove_remapping(intr); +} + +void ptintr_remove_intx_arch(struct ptintr *intr) +{ + /* disable interrupt */ + ioapic_gsi_mask_irq(ptirq_get_irq(intr->irq)); + remove_remapping(intr); +} + +void ptintr_init_arch(struct ptintr *(*find)(uint32_t, const union source_id *, + const struct acrn_vm *)) +{ + if (get_pcpu_id() == BSP_CPU_ID) { + find_intr = find; + } +} diff --git a/hypervisor/arch/x86/ptirq.c b/hypervisor/arch/x86/ptirq.c new file mode 100644 index 0000000000..fc775aefec --- /dev/null +++ b/hypervisor/arch/x86/ptirq.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#define DBG_LEVEL_PTIRQ 6U + +static void ptirq_handle_intx(const struct ptirq *irq) +{ + struct acrn_vm *vm = irq->vm; + const union source_id *virt_sid = &irq->virt_sid; + + switch (virt_sid->intx_id.ctlr) { + case INTX_CTLR_IOAPIC: { + union ioapic_rte rte; + bool trigger_lvl = false; + + /* INTX_CTLR_IOAPIC means we have vioapic enabled */ + vioapic_get_rte(vm, virt_sid->intx_id.gsi, &rte); + + if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) { + trigger_lvl = true; + } + + if (trigger_lvl) { + if (irq->polarity != 0U) { + vioapic_set_irqline_lock(vm, virt_sid->intx_id.gsi, GSI_SET_LOW); + } else { + vioapic_set_irqline_lock(vm, virt_sid->intx_id.gsi, GSI_SET_HIGH); + } + } else { + if (irq->polarity != 0U) { + vioapic_set_irqline_lock(vm, virt_sid->intx_id.gsi, GSI_FALLING_PULSE); + } else { + vioapic_set_irqline_lock(vm, virt_sid->intx_id.gsi, GSI_RAISING_PULSE); + } + } + + dev_dbg(DBG_LEVEL_PTIRQ, + "ptirq: irq=0x%x assert vr: 0x%x vRTE=0x%lx", + irq->allocated_pirq, irq_to_vector(irq->allocated_pirq), + rte.full); + break; + } + case INTX_CTLR_PIC: { + enum vpic_trigger trigger; + + /* INTX_CTLR_PIC means we have vpic enabled */ + vpic_get_irqline_trigger_mode(vm_pic(vm), virt_sid->intx_id.gsi, &trigger); + + if (trigger == LEVEL_TRIGGER) { + vpic_set_irqline_lock(vm_pic(vm), virt_sid->intx_id.gsi, GSI_SET_HIGH); + } else { + vpic_set_irqline_lock(vm_pic(vm), virt_sid->intx_id.gsi, GSI_RAISING_PULSE); + } + break; + } + default: + break; + } +} + +void ptirq_softirq_arch(struct ptirq *irq) +{ + struct msi_info *vmsi; + + /* handle real request */ + if (irq->intr_type == PTDEV_INTR_INTX) { + ptirq_handle_intx(irq); + } else { + vmsi = &irq->vmsi; + + /* TODO: vmsi destmode check required */ + (void)vlapic_inject_msi(irq->vm, vmsi->addr.full, vmsi->data.full); + + dev_dbg(DBG_LEVEL_PTIRQ, "ptirq: irq=0x%x MSI VR: 0x%x-0x%x", + irq->allocated_pirq, vmsi->data.bits.vector, + irq_to_vector(irq->allocated_pirq)); + dev_dbg(DBG_LEVEL_PTIRQ, " vmsi_addr: 0x%lx vmsi_data: 0x%x", + vmsi->addr.full, vmsi->data.full); + } +} + +uint32_t ptirq_get_irq_arch(uint32_t intr_type, union source_id *phys_sid) +{ + uint32_t phys_irq = IRQ_INVALID; + + if (intr_type == PTDEV_INTR_INTX) { + phys_irq = ioapic_gsi_to_irq(phys_sid->intx_id.gsi); + } + + return phys_irq; +} + +void ptirq_intx_ack_arch(struct ptirq *irq) +{ + uint32_t phys_irq = irq->allocated_pirq; + + if (irq->active) { + /* + * NOTE: only Level trigger will process EOI/ACK and if we got here + * means we have this vioapic or vpic or both enabled + */ + switch (irq->virt_sid.intx_id.ctlr) { + case INTX_CTLR_IOAPIC: + vioapic_set_irqline_nolock(irq->vm, irq->virt_sid.intx_id.gsi, + (irq->polarity == 0U) ? GSI_SET_LOW : GSI_SET_HIGH); + break; + case INTX_CTLR_PIC: + vpic_set_irqline_nolock(vm_pic(irq->vm), irq->virt_sid.intx_id.gsi, + GSI_SET_LOW); + break; + default: + break; + } + + dev_dbg(DBG_LEVEL_PTIRQ, "ptirq: irq=0x%x acked vr: 0x%x", + phys_irq, irq_to_vector(phys_irq)); + ioapic_gsi_unmask_irq(phys_irq); + } +} diff --git a/hypervisor/arch/x86/rdt.c b/hypervisor/arch/x86/rdt.c index e33e1b3aaf..f356723534 100644 --- a/hypervisor/arch/x86/rdt.c +++ b/hypervisor/arch/x86/rdt.c @@ -5,17 +5,16 @@ */ #include -#include -#include -#include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include const uint16_t hv_clos = 0U; /* RDT features can support different numbers of CLOS. Set the lowers numerical diff --git a/hypervisor/arch/x86/rtcm.c b/hypervisor/arch/x86/rtcm.c index e40824a7cf..b70ab64c82 100644 --- a/hypervisor/arch/x86/rtcm.c +++ b/hypervisor/arch/x86/rtcm.c @@ -4,12 +4,12 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include -#include +#include #include #include #include -#include -#include +#include +#include static uint64_t software_sram_bottom_hpa; diff --git a/hypervisor/arch/x86/security.c b/hypervisor/arch/x86/security.c index a065c19e01..6989e7d8a6 100644 --- a/hypervisor/arch/x86/security.c +++ b/hypervisor/arch/x86/security.c @@ -5,12 +5,11 @@ */ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include static bool skip_l1dfl_vmentry; @@ -194,11 +193,10 @@ bool is_ept_force_4k_ipage(void) bool is_ept_force_4k_ipage(void) { bool force_4k_ipage = true; - const struct cpuinfo_x86 *info = get_pcpu_info(); uint64_t x86_arch_capabilities; - if (info->displayfamily == 0x6U) { - switch (info->displaymodel) { + if (pcpu_family_id() == 0x6U) { + switch (pcpu_model_id()) { case 0x26U: case 0x27U: case 0x35U: diff --git a/hypervisor/arch/x86/seed/seed_abl.c b/hypervisor/arch/x86/seed/seed_abl.c deleted file mode 100644 index 37133c60d7..0000000000 --- a/hypervisor/arch/x86/seed/seed_abl.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include -#include -#include -#include "seed_abl.h" - -#define ABL_SEED_LEN 32U -struct abl_seed_info { - uint8_t svn; - uint8_t reserved[3]; - uint8_t seed[ABL_SEED_LEN]; -}; - -#define ABL_SEED_LIST_MAX 4U -struct abl_svn_seed { - uint32_t size_of_this_struct; - uint32_t version; - uint32_t num_seeds; - struct abl_seed_info seed_list[ABL_SEED_LIST_MAX]; -}; - -/* - * parse_seed_abl - * - * description: - * This function parse seed_list which provided by ABL. - * - * input: - * cmdline pointer to cmdline string - * - * output: - * phy_seed pointer to physical seed structure - * - * return value: - * true if parse successfully, otherwise false. - */ -bool parse_seed_abl(uint64_t addr, struct physical_seed *phy_seed) -{ - uint32_t i; - uint32_t legacy_seed_index = 0U; - struct seed_info *seed_list; - struct abl_svn_seed *abl_seed = (struct abl_svn_seed *)hpa2hva(addr); - bool status = false; - - if ((phy_seed != NULL) && (abl_seed != NULL) && - (abl_seed->num_seeds >= 2U) && (abl_seed->num_seeds <= ABL_SEED_LIST_MAX)) { - - seed_list = phy_seed->seed_list; - /* - * The seed_list from ABL contains several seeds which based on SVN - * and one legacy seed which is not based on SVN. The legacy seed's - * svn value is minimum in the seed list. And CSE ensures at least two - * seeds will be generated which will contain the legacy seed. - * Here find the legacy seed index first. - */ - for (i = 1U; i < abl_seed->num_seeds; i++) { - if (abl_seed->seed_list[i].svn < abl_seed->seed_list[legacy_seed_index].svn) { - legacy_seed_index = i; - } - } - - /* - * Copy out abl_seed for trusty and clear the original seed in memory. - * The SOS requires the legacy seed to derive RPMB key. So skip the - * legacy seed when clear original seed. - */ - (void)memset((void *)&phy_seed->seed_list[0U], 0U, sizeof(phy_seed->seed_list)); - for (i = 0U; i < abl_seed->num_seeds; i++) { - seed_list[i].cse_svn = abl_seed->seed_list[i].svn; - (void)memcpy_s((void *)&seed_list[i].seed[0U], sizeof(seed_list[i].seed), - (void *)&abl_seed->seed_list[i].seed[0U], sizeof(abl_seed->seed_list[i].seed)); - - if (i == legacy_seed_index) { - continue; - } - - (void)memset((void *)&abl_seed->seed_list[i].seed[0U], 0U, - sizeof(abl_seed->seed_list[i].seed)); - } - - phy_seed->num_seeds = abl_seed->num_seeds; - status = true; - } - - return status; -} diff --git a/hypervisor/arch/x86/seed/seed_abl.h b/hypervisor/arch/x86/seed/seed_abl.h deleted file mode 100644 index a87647939a..0000000000 --- a/hypervisor/arch/x86/seed/seed_abl.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef SEED_ABL_H_ -#define SEED_ABL_H_ - -bool parse_seed_abl(uint64_t addr, struct physical_seed *phy_seed); - -#endif /* SEED_ABL_H_ */ diff --git a/hypervisor/arch/x86/seed/seed_sbl.c b/hypervisor/arch/x86/seed/seed_sbl.c deleted file mode 100644 index d1f7b60881..0000000000 --- a/hypervisor/arch/x86/seed/seed_sbl.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include -#include -#include -#include -#include "seed_sbl.h" - -#define SEED_ENTRY_TYPE_SVNSEED 0x1U -/* #define SEED_ENTRY_TYPE_RPMBSEED 0x2U */ - -/* #define SEED_ENTRY_USAGE_USEED 0x1U */ -#define SEED_ENTRY_USAGE_DSEED 0x2U - -struct seed_list_hob { - uint8_t revision; - uint8_t reserved0[3]; - uint32_t buffer_size; - uint8_t total_seed_count; - uint8_t reserved1[3]; -}; - -struct seed_entry { - /* SVN based seed or RPMB seed or attestation key_box */ - uint8_t type; - /* For SVN seed: useed or dseed - * For RPMB seed: serial number based or not - */ - uint8_t usage; - /* index for the same type and usage seed */ - uint8_t index; - uint8_t reserved; - /* reserved for future use */ - uint16_t flags; - /* Total size of this seed entry */ - uint16_t seed_entry_size; - /* SVN seed: struct seed_info - * RPMB seed: uint8_t rpmb_key[key_len] - */ - uint8_t seed[0]; -}; - -/* - * parse_seed_sbl - * - * description: - * This function parse seed_list which provided by SBL - * - * input: - * cmdline pointer to cmdline string - * - * return value: - * true if parse successfully, otherwise false. - */ -bool parse_seed_sbl(uint64_t addr, struct physical_seed *phy_seed) -{ - uint8_t i; - uint8_t dseed_index = 0U; - struct image_boot_params *boot_params = NULL; - struct seed_list_hob *seed_hob = NULL; - struct seed_entry *entry = NULL; - struct seed_info *seed_list = NULL; - bool status = false; - - boot_params = (struct image_boot_params *)hpa2hva(addr); - - if (boot_params != NULL) { - seed_hob = (struct seed_list_hob *)hpa2hva(boot_params->p_seed_list); - } - - if ((seed_hob != NULL) && (phy_seed != NULL)) { - status = true; - - seed_list = phy_seed->seed_list; - - entry = (struct seed_entry *)((uint8_t *)seed_hob + sizeof(struct seed_list_hob)); - - for (i = 0U; i < seed_hob->total_seed_count; i++) { - if (entry != NULL) { - /* retrieve dseed */ - if ((SEED_ENTRY_TYPE_SVNSEED == entry->type) && - (SEED_ENTRY_USAGE_DSEED == entry->usage)) { - - /* The seed_entry with same type/usage are always - * arranged by index in order of 0~3. - */ - if ((entry->index != dseed_index) || - (entry->index >= BOOTLOADER_SEED_MAX_ENTRIES)) { - status = false; - break; - } - - (void)memcpy_s((void *)&seed_list[dseed_index], sizeof(struct seed_info), - (void *)&entry->seed[0U], sizeof(struct seed_info)); - dseed_index++; - - /* erase original seed in seed entry */ - (void)memset((void *)&entry->seed[0U], 0U, sizeof(struct seed_info)); - } - - entry = (struct seed_entry *)((uint8_t *)entry + entry->seed_entry_size); - } - } - - if (status) { - phy_seed->num_seeds = dseed_index; - } - } - - return status; -} diff --git a/hypervisor/arch/x86/seed/seed_sbl.h b/hypervisor/arch/x86/seed/seed_sbl.h deleted file mode 100644 index a0668170f8..0000000000 --- a/hypervisor/arch/x86/seed/seed_sbl.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef SEED_SBL_H_ -#define SEED_SBL_H_ - -struct image_boot_params { - uint32_t size_of_this_struct; - uint32_t version; - uint64_t p_seed_list; - uint64_t p_platform_info; - uint64_t reserved; -}; - -bool parse_seed_sbl(uint64_t addr, struct physical_seed *phy_seed); - -#endif /* SEED_SBL_H_ */ diff --git a/hypervisor/arch/x86/sgx.c b/hypervisor/arch/x86/sgx.c index 0ff324c577..76b34a2547 100644 --- a/hypervisor/arch/x86/sgx.c +++ b/hypervisor/arch/x86/sgx.c @@ -6,11 +6,10 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include #define SGX_OPTED_IN (MSR_IA32_FEATURE_CONTROL_SGX_GE | MSR_IA32_FEATURE_CONTROL_LOCK) diff --git a/hypervisor/arch/x86/timer.c b/hypervisor/arch/x86/timer.c deleted file mode 100644 index 0f10ce327f..0000000000 --- a/hypervisor/arch/x86/timer.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_TIMER_ACTIONS 32U -#define CAL_MS 10U -#define MIN_TIMER_PERIOD_US 500U - -static uint32_t tsc_khz = 0U; - -uint64_t rdtsc(void) -{ - uint32_t lo, hi; - - asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); - return ((uint64_t)hi << 32U) | lo; -} - -static void run_timer(const struct hv_timer *timer) -{ - /* deadline = 0 means stop timer, we should skip */ - if ((timer->func != NULL) && (timer->fire_tsc != 0UL)) { - timer->func(timer->priv_data); - } - - TRACE_2L(TRACE_TIMER_ACTION_PCKUP, timer->fire_tsc, 0UL); -} - -/* run in interrupt context */ -static void tsc_deadline_handler(__unused uint32_t irq, __unused void *data) -{ - fire_softirq(SOFTIRQ_TIMER); -} - -static inline void update_physical_timer(struct per_cpu_timers *cpu_timer) -{ - struct hv_timer *timer = NULL; - - /* find the next event timer */ - if (!list_empty(&cpu_timer->timer_list)) { - timer = container_of((&cpu_timer->timer_list)->next, - struct hv_timer, node); - - /* it is okay to program a expired time */ - msr_write(MSR_IA32_TSC_DEADLINE, timer->fire_tsc); - } -} - -/* - * return true if we add the timer on the timer_list head - */ -static bool local_add_timer(struct per_cpu_timers *cpu_timer, - struct hv_timer *timer) -{ - struct list_head *pos, *prev; - struct hv_timer *tmp; - uint64_t tsc = timer->fire_tsc; - - prev = &cpu_timer->timer_list; - list_for_each(pos, &cpu_timer->timer_list) { - tmp = container_of(pos, struct hv_timer, node); - if (tmp->fire_tsc < tsc) { - prev = &tmp->node; - } - else { - break; - } - } - - list_add(&timer->node, prev); - - return (prev == &cpu_timer->timer_list); -} - -int32_t add_timer(struct hv_timer *timer) -{ - struct per_cpu_timers *cpu_timer; - uint16_t pcpu_id; - int32_t ret = 0; - uint64_t rflags; - - if ((timer == NULL) || (timer->func == NULL) || (timer->fire_tsc == 0UL)) { - ret = -EINVAL; - } else { - ASSERT(list_empty(&timer->node), "add timer again!\n"); - - /* limit minimal periodic timer cycle period */ - if (timer->mode == TICK_MODE_PERIODIC) { - timer->period_in_cycle = max(timer->period_in_cycle, us_to_ticks(MIN_TIMER_PERIOD_US)); - } - - pcpu_id = get_pcpu_id(); - cpu_timer = &per_cpu(cpu_timers, pcpu_id); - - CPU_INT_ALL_DISABLE(&rflags); - /* update the physical timer if we're on the timer_list head */ - if (local_add_timer(cpu_timer, timer)) { - update_physical_timer(cpu_timer); - } - CPU_INT_ALL_RESTORE(rflags); - - TRACE_2L(TRACE_TIMER_ACTION_ADDED, timer->fire_tsc, 0UL); - } - - return ret; - -} - -void del_timer(struct hv_timer *timer) -{ - uint64_t rflags; - - CPU_INT_ALL_DISABLE(&rflags); - if ((timer != NULL) && !list_empty(&timer->node)) { - list_del_init(&timer->node); - } - CPU_INT_ALL_RESTORE(rflags); -} - -static void init_percpu_timer(uint16_t pcpu_id) -{ - struct per_cpu_timers *cpu_timer; - - cpu_timer = &per_cpu(cpu_timers, pcpu_id); - INIT_LIST_HEAD(&cpu_timer->timer_list); -} - -static void init_tsc_deadline_timer(void) -{ - uint32_t val; - - val = TIMER_VECTOR; - val |= APIC_LVTT_TM_TSCDLT; /* TSC deadline and unmask */ - msr_write(MSR_IA32_EXT_APIC_LVT_TIMER, val); - cpu_memory_barrier(); - - /* disarm timer */ - msr_write(MSR_IA32_TSC_DEADLINE, 0UL); -} - -static void timer_softirq(uint16_t pcpu_id) -{ - struct per_cpu_timers *cpu_timer; - struct hv_timer *timer; - struct list_head *pos, *n; - uint32_t tries = MAX_TIMER_ACTIONS; - uint64_t current_tsc = rdtsc(); - - /* handle passed timer */ - cpu_timer = &per_cpu(cpu_timers, pcpu_id); - - /* This is to make sure we are not blocked due to delay inside func() - * force to exit irq handler after we serviced >31 timers - * caller used to local_add_timer() for periodic timer, if there is a delay - * inside func(), it will infinitely loop here, because new added timer - * already passed due to previously func()'s delay. - */ - list_for_each_safe(pos, n, &cpu_timer->timer_list) { - timer = container_of(pos, struct hv_timer, node); - /* timer expried */ - tries--; - if ((timer->fire_tsc <= current_tsc) && (tries != 0U)) { - del_timer(timer); - - run_timer(timer); - - if (timer->mode == TICK_MODE_PERIODIC) { - /* update periodic timer fire tsc */ - timer->fire_tsc += timer->period_in_cycle; - (void)local_add_timer(cpu_timer, timer); - } - } else { - break; - } - } - - /* update nearest timer */ - update_physical_timer(cpu_timer); -} - -void timer_init(void) -{ - uint16_t pcpu_id = get_pcpu_id(); - int32_t retval = 0; - - init_percpu_timer(pcpu_id); - - if (pcpu_id == BSP_CPU_ID) { - register_softirq(SOFTIRQ_TIMER, timer_softirq); - - retval = request_irq(TIMER_IRQ, (irq_action_t)tsc_deadline_handler, NULL, IRQF_NONE); - if (retval < 0) { - pr_err("Timer setup failed"); - } - } - - if (retval >= 0) { - init_tsc_deadline_timer(); - } -} - -static uint64_t pit_calibrate_tsc(uint32_t cal_ms_arg) -{ -#define PIT_TICK_RATE 1193182U -#define PIT_TARGET 0x3FFFU -#define PIT_MAX_COUNT 0xFFFFU - - uint32_t cal_ms = cal_ms_arg; - uint32_t initial_pit; - uint16_t current_pit; - uint32_t max_cal_ms; - uint64_t current_tsc; - uint8_t initial_pit_high, initial_pit_low; - - max_cal_ms = ((PIT_MAX_COUNT - PIT_TARGET) * 1000U) / PIT_TICK_RATE; - cal_ms = min(cal_ms, max_cal_ms); - - /* Assume the 8254 delivers 18.2 ticks per second when 16 bits fully - * wrap. This is about 1.193MHz or a clock period of 0.8384uSec - */ - initial_pit = (cal_ms * PIT_TICK_RATE) / 1000U; - initial_pit += PIT_TARGET; - initial_pit_high = (uint8_t)(initial_pit >> 8U); - initial_pit_low = (uint8_t)initial_pit; - - /* Port 0x43 ==> Control word write; Data 0x30 ==> Select Counter 0, - * Read/Write least significant byte first, mode 0, 16 bits. - */ - - pio_write8(0x30U, 0x43U); - pio_write8(initial_pit_low, 0x40U); /* Write LSB */ - pio_write8(initial_pit_high, 0x40U); /* Write MSB */ - - current_tsc = rdtsc(); - - do { - /* Port 0x43 ==> Control word write; 0x00 ==> Select - * Counter 0, Counter Latch Command, Mode 0; 16 bits - */ - pio_write8(0x00U, 0x43U); - - current_pit = (uint16_t)pio_read8(0x40U); /* Read LSB */ - current_pit |= (uint16_t)pio_read8(0x40U) << 8U; /* Read MSB */ - /* Let the counter count down to PIT_TARGET */ - } while (current_pit > PIT_TARGET); - - current_tsc = rdtsc() - current_tsc; - - return (current_tsc / cal_ms) * 1000U; -} - -/* - * Determine TSC frequency via CPUID 0x15 and 0x16. - */ -static uint64_t native_calibrate_tsc(void) -{ - uint64_t tsc_hz = 0UL; - struct cpuinfo_x86 *cpu_info = get_pcpu_info(); - - if (cpu_info->cpuid_level >= 0x15U) { - uint32_t eax_denominator, ebx_numerator, ecx_hz, reserved; - - cpuid_subleaf(0x15U, 0x0U, &eax_denominator, &ebx_numerator, - &ecx_hz, &reserved); - - if ((eax_denominator != 0U) && (ebx_numerator != 0U)) { - tsc_hz = ((uint64_t) ecx_hz * - ebx_numerator) / eax_denominator; - } - } - - if ((tsc_hz == 0UL) && (cpu_info->cpuid_level >= 0x16U)) { - uint32_t eax_base_mhz, ebx_max_mhz, ecx_bus_mhz, edx; - cpuid_subleaf(0x16U, 0x0U, &eax_base_mhz, &ebx_max_mhz, &ecx_bus_mhz, &edx); - tsc_hz = (uint64_t) eax_base_mhz * 1000000U; - } - - return tsc_hz; -} - -void calibrate_tsc(void) -{ - uint64_t tsc_hz; - tsc_hz = native_calibrate_tsc(); - if (tsc_hz == 0U) { - tsc_hz = pit_calibrate_tsc(CAL_MS); - } - tsc_khz = (uint32_t)(tsc_hz / 1000UL); - printf("%s, tsc_khz=%lu\n", __func__, tsc_khz); -} - -uint32_t get_tsc_khz(void) -{ - return tsc_khz; -} - -/** - * Frequency of TSC in KHz (where 1KHz = 1000Hz). Only valid after - * calibrate_tsc() returns. - */ - -uint64_t us_to_ticks(uint32_t us) -{ - return (((uint64_t)us * (uint64_t)tsc_khz) / 1000UL); -} - -uint64_t ticks_to_us(uint64_t ticks) -{ - uint64_t us = 0UL; - - if (tsc_khz != 0U ) { - us = (ticks * 1000UL) / (uint64_t)tsc_khz; - } - - return us; -} - -uint64_t ticks_to_ms(uint64_t ticks) -{ - return ticks / (uint64_t)tsc_khz; -} - -void udelay(uint32_t us) -{ - uint64_t dest_tsc, delta_tsc; - - /* Calculate number of ticks to wait */ - delta_tsc = us_to_ticks(us); - dest_tsc = rdtsc() + delta_tsc; - - /* Loop until time expired */ - while (rdtsc() < dest_tsc) { - } -} diff --git a/hypervisor/arch/x86/trampoline.c b/hypervisor/arch/x86/trampoline.c index 19139081a4..53b00c6220 100644 --- a/hypervisor/arch/x86/trampoline.c +++ b/hypervisor/arch/x86/trampoline.c @@ -5,12 +5,12 @@ */ #include -#include -#include -#include +#include +#include +#include #include -#include -#include +#include +#include static uint64_t trampoline_start16_paddr; diff --git a/hypervisor/arch/x86/tsc.c b/hypervisor/arch/x86/tsc.c new file mode 100644 index 0000000000..0203efef57 --- /dev/null +++ b/hypervisor/arch/x86/tsc.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#define CAL_MS 10U + +/** + * Frequency in KHz (where 1KHz = 1000Hz). Only valid after + * calibrate_tsc() returns. + */ +static uint32_t tsc_khz = 0U; + +static uint64_t rdtsc(void) +{ + uint32_t lo, hi; + + asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); + return ((uint64_t)hi << 32U) | lo; +} + +uint32_t get_cpu_freq(void) +{ + return tsc_khz; +} + +uint64_t get_cpu_cycles(void) +{ + return rdtsc(); +} + +static uint64_t pit_calibrate_tsc(uint32_t cal_ms_arg) +{ +#define PIT_TICK_RATE 1193182U +#define PIT_TARGET 0x3FFFU +#define PIT_MAX_COUNT 0xFFFFU + + uint32_t cal_ms = cal_ms_arg; + uint32_t initial_pit; + uint16_t current_pit; + uint32_t max_cal_ms; + uint64_t current_tsc; + uint8_t initial_pit_high, initial_pit_low; + + max_cal_ms = ((PIT_MAX_COUNT - PIT_TARGET) * 1000U) / PIT_TICK_RATE; + cal_ms = min(cal_ms, max_cal_ms); + + /* Assume the 8254 delivers 18.2 ticks per second when 16 bits fully + * wrap. This is about 1.193MHz or a clock period of 0.8384uSec + */ + initial_pit = (cal_ms * PIT_TICK_RATE) / 1000U; + initial_pit += PIT_TARGET; + initial_pit_high = (uint8_t)(initial_pit >> 8U); + initial_pit_low = (uint8_t)initial_pit; + + /* Port 0x43 ==> Control word write; Data 0x30 ==> Select Counter 0, + * Read/Write least significant byte first, mode 0, 16 bits. + */ + + pio_write8(0x30U, 0x43U); + pio_write8(initial_pit_low, 0x40U); /* Write LSB */ + pio_write8(initial_pit_high, 0x40U); /* Write MSB */ + + current_tsc = rdtsc(); + + do { + /* Port 0x43 ==> Control word write; 0x00 ==> Select + * Counter 0, Counter Latch Command, Mode 0; 16 bits + */ + pio_write8(0x00U, 0x43U); + + current_pit = (uint16_t)pio_read8(0x40U); /* Read LSB */ + current_pit |= (uint16_t)pio_read8(0x40U) << 8U; /* Read MSB */ + /* Let the counter count down to PIT_TARGET */ + } while (current_pit > PIT_TARGET); + + current_tsc = rdtsc() - current_tsc; + + return (current_tsc / cal_ms) * 1000U; +} + +/* + * Determine TSC frequency via CPUID 0x15 and 0x16. + */ +static uint64_t native_calibrate_tsc(void) +{ + uint64_t tsc_hz = 0UL; + + if (pcpu_cpuid_level() >= 0x15U) { + uint32_t eax_denominator, ebx_numerator, ecx_hz, reserved; + + cpuid_subleaf(0x15U, 0x0U, &eax_denominator, &ebx_numerator, + &ecx_hz, &reserved); + + if ((eax_denominator != 0U) && (ebx_numerator != 0U)) { + tsc_hz = ((uint64_t) ecx_hz * + ebx_numerator) / eax_denominator; + } + } + + if ((tsc_hz == 0UL) && (pcpu_cpuid_level() >= 0x16U)) { + uint32_t eax_base_mhz, ebx_max_mhz, ecx_bus_mhz, edx; + + cpuid_subleaf(0x16U, 0x0U, &eax_base_mhz, &ebx_max_mhz, &ecx_bus_mhz, &edx); + tsc_hz = (uint64_t) eax_base_mhz * 1000000U; + } + + return tsc_hz; +} + +void calibrate_tsc(void) +{ + uint64_t tsc_hz; + + tsc_hz = native_calibrate_tsc(); + if (tsc_hz == 0U) { + tsc_hz = pit_calibrate_tsc(CAL_MS); + } + tsc_khz = (uint32_t)(tsc_hz / 1000UL); +} diff --git a/hypervisor/arch/x86/tsc_deadline_timer.c b/hypervisor/arch/x86/tsc_deadline_timer.c new file mode 100644 index 0000000000..b8da39e117 --- /dev/null +++ b/hypervisor/arch/x86/tsc_deadline_timer.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* run in interrupt context */ +static void timer_expired_handler(__unused uint32_t irq, __unused void *data) +{ + fire_softirq(SOFTIRQ_TIMER); +} + +void set_hw_timeout(uint64_t timeout) +{ + msr_write(MSR_IA32_TSC_DEADLINE, timeout); +} + +void init_hw_timer(void) +{ + uint32_t val; + int32_t retval = 0; + + if (get_pcpu_id() == BSP_CPU_ID) { + retval = request_irq(TIMER_IRQ, (irq_action_t)timer_expired_handler, NULL, IRQF_NONE); + if (retval < 0) { + pr_err("Timer setup failed"); + } + } + + if (retval >= 0) { + val = TIMER_VECTOR; + val |= APIC_LVTT_TM_TSCDLT; /* TSC deadline and unmask */ + msr_write(MSR_IA32_EXT_APIC_LVT_TIMER, val); + cpu_memory_barrier(); + + /* disarm timer */ + msr_write(MSR_IA32_TSC_DEADLINE, 0UL); + } +} diff --git a/hypervisor/arch/x86/vmx.c b/hypervisor/arch/x86/vmx.c index bc6e049ae7..613935b1b2 100644 --- a/hypervisor/arch/x86/vmx.c +++ b/hypervisor/arch/x86/vmx.c @@ -7,10 +7,10 @@ */ #include -#include -#include -#include -#include +#include +#include +#include +#include /** * @pre addr != NULL && addr is 4KB-aligned diff --git a/hypervisor/arch/x86/vtd.c b/hypervisor/arch/x86/vtd.c index 39fd98ce43..2fa2226a05 100644 --- a/hypervisor/arch/x86/vtd.c +++ b/hypervisor/arch/x86/vtd.c @@ -7,22 +7,26 @@ #define pr_prefix "iommu: " #include -#include +#include #include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include +#include #include -#include +#include +#include #define DBG_IOMMU 0 @@ -248,11 +252,11 @@ static inline void dmar_wait_completion(const struct dmar_drhd_rt *dmar_unit, ui uint32_t mask, uint32_t pre_condition, uint32_t *status) { /* variable start isn't used when built as release version */ - __unused uint64_t start = rdtsc(); + __unused uint64_t start = get_cpu_cycles(); do { *status = iommu_read32(dmar_unit, offset); - ASSERT(((rdtsc() - start) < CYCLES_PER_MS), + ASSERT(((get_cpu_cycles() - start) < CYCLES_PER_MS), "DMAR OP Timeout!"); asm_pause(); } while( (*status & mask) == pre_condition); @@ -568,9 +572,9 @@ static void dmar_issue_qi_request(struct dmar_drhd_rt *dmar_unit, struct dmar_en qi_status = DMAR_INV_STATUS_INCOMPLETE; iommu_write32(dmar_unit, DMAR_IQT_REG, dmar_unit->qi_tail); - start = rdtsc(); + start = get_cpu_cycles(); while (qi_status != DMAR_INV_STATUS_COMPLETED) { - if ((rdtsc() - start) > CYCLES_PER_MS) { + if ((get_cpu_cycles() - start) > CYCLES_PER_MS) { pr_err("DMAR OP Timeout! @ %s", __func__); break; } diff --git a/hypervisor/boot/acpi_base.c b/hypervisor/boot/acpi_base.c index bc3e7d2cdf..6820bea6bd 100644 --- a/hypervisor/boot/acpi_base.c +++ b/hypervisor/boot/acpi_base.c @@ -29,12 +29,13 @@ #include #include #include "acpi.h" -#include -#include +#include +#include +#include #include #include #include -#include +#include #include static struct acpi_table_rsdp *acpi_rsdp; diff --git a/hypervisor/boot/guest/vboot_info.c b/hypervisor/boot/guest/vboot_info.c index 71aad89210..b662f374c0 100644 --- a/hypervisor/boot/guest/vboot_info.c +++ b/hypervisor/boot/guest/vboot_info.c @@ -7,14 +7,17 @@ #include #include #include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/hypervisor/boot/multiboot/multiboot.c b/hypervisor/boot/multiboot/multiboot.c index fc2095a3fe..81ad82f17a 100644 --- a/hypervisor/boot/multiboot/multiboot.c +++ b/hypervisor/boot/multiboot/multiboot.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include diff --git a/hypervisor/boot/multiboot/multiboot2.c b/hypervisor/boot/multiboot/multiboot2.c index e3611ac905..3ffeefabe2 100644 --- a/hypervisor/boot/multiboot/multiboot2.c +++ b/hypervisor/boot/multiboot/multiboot2.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "multiboot_priv.h" /** diff --git a/hypervisor/boot/reloc.c b/hypervisor/boot/reloc.c index dea5a694de..bc4d284129 100644 --- a/hypervisor/boot/reloc.c +++ b/hypervisor/boot/reloc.c @@ -6,7 +6,7 @@ #include #include -#include +#include #ifdef CONFIG_RELOC #define DT_NULL 0U /* end of .dynamic section */ diff --git a/hypervisor/common/cycles.c b/hypervisor/common/cycles.c new file mode 100644 index 0000000000..475026a955 --- /dev/null +++ b/hypervisor/common/cycles.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +uint64_t us_to_cycles(uint32_t us) +{ + return (((uint64_t)us * (uint64_t)get_cpu_freq()) / 1000UL); +} + +uint64_t cycles_to_us(uint64_t ticks) +{ + uint64_t us = 0UL, cpu_freq_khz = (uint64_t)get_cpu_freq(); + + if (cpu_freq_khz != 0U ) { + us = (ticks * 1000UL) / cpu_freq_khz; + } + + return us; +} + +uint64_t cycles_to_ms(uint64_t ticks) +{ + return ticks / (uint64_t)get_cpu_freq(); +} diff --git a/hypervisor/common/event.c b/hypervisor/common/event.c index b984945284..8cc77fabd3 100644 --- a/hypervisor/common/event.c +++ b/hypervisor/common/event.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include #include #include #include diff --git a/hypervisor/common/hv_main.c b/hypervisor/common/hv_main.c index 1975058adf..1dd31ca2b7 100644 --- a/hypervisor/common/hv_main.c +++ b/hypervisor/common/hv_main.c @@ -4,10 +4,14 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index 5c4e7dfa13..2cba645d00 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -4,25 +4,25 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include -#include +#include #include #include #include -#include +#include #define DBG_LEVEL_HYCALL 6U @@ -412,7 +412,7 @@ int32_t hcall_set_irqline(struct acrn_vm *vm, struct acrn_vm *target_vm, __unuse * number #2 to PIC IRQ #0. */ irq_pic = (ops->gsi == 2U) ? 0U : ops->gsi; - vpic_set_irqline(vm_pic(target_vm), irq_pic, ops->op); + vpic_set_irqline_lock(vm_pic(target_vm), irq_pic, ops->op); } /* handle IOAPIC irqline */ @@ -922,6 +922,7 @@ int32_t hcall_set_ptdev_intr_info(struct acrn_vm *vm, struct acrn_vm *target_vm, struct pci_vdev *vdev; union pci_bdf bdf = {.value = irq.virt_bdf}; struct acrn_vpci *vpci = &target_vm->vpci; + struct ptintr_add_args intx_add; spinlock_obtain(&vpci->lock); vdev = pci_find_vdev(vpci, bdf); @@ -935,8 +936,13 @@ int32_t hcall_set_ptdev_intr_info(struct acrn_vm *vm, struct acrn_vm *target_vm, if ((((!irq.intx.pic_pin) && (irq.intx.virt_pin < get_vm_gsicount(target_vm))) || ((irq.intx.pic_pin) && (irq.intx.virt_pin < vpic_pincount()))) && is_gsi_valid(irq.intx.phys_pin)) { - ret = ptirq_add_intx_remapping(target_vm, irq.intx.virt_pin, - irq.intx.phys_pin, irq.intx.pic_pin); + intx_add.intr_type = PTDEV_INTR_INTX; + intx_add.intx.virt_gsi = irq.intx.virt_pin; + intx_add.intx.virt_ctlr = irq.intx.pic_pin ? + INTX_CTLR_PIC : INTX_CTLR_IOAPIC; + intx_add.intx.phys_gsi = irq.intx.phys_pin; + intx_add.intx.phys_ctlr = INTX_CTLR_IOAPIC; + ret = ptintr_add(target_vm, &intx_add); } else { pr_err("%s: Invalid phys pin or virt pin\n", __func__); } @@ -973,6 +979,7 @@ int32_t hcall_reset_ptdev_intr_info(struct acrn_vm *vm, struct acrn_vm *target_v struct pci_vdev *vdev; union pci_bdf bdf = {.value = irq.virt_bdf}; struct acrn_vpci *vpci = &target_vm->vpci; + struct ptintr_rmv_args intx_rmv; spinlock_obtain(&vpci->lock); vdev = pci_find_vdev(vpci, bdf); @@ -985,7 +992,11 @@ int32_t hcall_reset_ptdev_intr_info(struct acrn_vm *vm, struct acrn_vm *target_v if ((vdev != NULL) && (vdev->pdev->bdf.value == irq.phys_bdf)) { if (((!irq.intx.pic_pin) && (irq.intx.virt_pin < get_vm_gsicount(target_vm))) || ((irq.intx.pic_pin) && (irq.intx.virt_pin < vpic_pincount()))) { - ptirq_remove_intx_remapping(target_vm, irq.intx.virt_pin, irq.intx.pic_pin); + intx_rmv.intr_type = PTDEV_INTR_INTX; + intx_rmv.intx.virt_gsi = irq.intx.virt_pin; + intx_rmv.intx.virt_ctlr = irq.intx.pic_pin ? + INTX_CTLR_PIC : INTX_CTLR_IOAPIC; + ptintr_remove_and_unmap(target_vm, &intx_rmv); ret = 0; } else { pr_err("%s: Invalid virt pin\n", __func__); @@ -1104,7 +1115,7 @@ int32_t hcall_vm_intr_monitor(struct acrn_vm *vm, struct acrn_vm *target_vm, __u if (intr_hdr->buf_cnt <= (MAX_PTDEV_NUM * 2U)) { switch (intr_hdr->cmd) { case INTR_CMD_GET_DATA: - intr_hdr->buf_cnt = ptirq_get_intr_data(target_vm, + intr_hdr->buf_cnt = ptintr_get_intr_data(target_vm, intr_hdr->buffer, intr_hdr->buf_cnt); break; diff --git a/hypervisor/common/irq.c b/hypervisor/common/irq.c new file mode 100644 index 0000000000..c121a0b694 --- /dev/null +++ b/hypervisor/common/irq.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static spinlock_t irq_alloc_spinlock = { .head = 0U, .tail = 0U, }; + +uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE]; +static uint64_t irq_rsvd_bitmap[IRQ_ALLOC_BITMAP_SIZE]; +struct irq_desc irq_desc_array[NR_IRQS]; + +/* + * alloc an free irq if req_irq is IRQ_INVALID, or else set assigned + * return: irq num on success, IRQ_INVALID on failure + */ +static uint32_t alloc_irq_num(uint32_t req_irq, bool reserve) +{ + uint32_t irq = req_irq; + uint64_t rflags; + uint32_t ret; + + if ((irq >= NR_IRQS) && (irq != IRQ_INVALID)) { + pr_err("[%s] invalid req_irq %u", __func__, req_irq); + ret = IRQ_INVALID; + } else { + spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); + if (irq == IRQ_INVALID) { + /* if no valid irq num given, find a free one */ + irq = (uint32_t)ffz64_ex(irq_alloc_bitmap, NR_IRQS); + } + + if (irq >= NR_IRQS) { + irq = IRQ_INVALID; + } else { + bitmap_set_nolock((uint16_t)(irq & 0x3FU), + irq_alloc_bitmap + (irq >> 6U)); + + if (reserve == true) { + bitmap_set_nolock((uint16_t)(irq & 0x3FU), + irq_rsvd_bitmap + (irq >> 6U)); + } + } + spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); + ret = irq; + } + return ret; +} + +uint32_t reserve_irq_num(uint32_t req_irq) +{ + return alloc_irq_num(req_irq, true); +} + +/* + * @pre: irq is not in irq_static_mappings + * free irq num allocated via alloc_irq_num() + */ +static void free_irq_num(uint32_t irq) +{ + uint64_t rflags; + + if (irq < NR_IRQS) { + spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); + + if (bitmap_test((uint16_t)(irq & 0x3FU), + irq_rsvd_bitmap + (irq >> 6U)) == false) { + bitmap_clear_nolock((uint16_t)(irq & 0x3FU), + irq_alloc_bitmap + (irq >> 6U)); + } + spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); + } +} + +/* + * There are four cases as to irq/vector allocation: + * case 1: req_irq = IRQ_INVALID + * caller did not know which irq to use, and want system to + * allocate available irq for it. These irq are in range: + * nr_gsi ~ NR_IRQS + * an irq will be allocated and a vector will be assigned to this + * irq automatically. + * case 2: req_irq >= NR_LAGACY_IRQ and irq < nr_gsi + * caller want to add device ISR handler into ioapic pins. + * a vector will automatically assigned. + * case 3: req_irq >=0 and req_irq < NR_LEGACY_IRQ + * caller want to add device ISR handler into ioapic pins, which + * is a legacy irq, vector already reserved. + * Nothing to do in this case. + * case 4: irq with speical type (not from IOAPIC/MSI) + * These irq value are pre-defined for Timer, IPI, Spurious etc, + * which is listed in irq_static_mappings[]. + * Nothing to do in this case. + * + * return value: valid irq (>=0) on success, otherwise errno (< 0). + */ +int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, + uint32_t flags) +{ + struct irq_desc *desc; + uint32_t irq; + uint64_t rflags; + int32_t ret; + + irq = alloc_irq_num(req_irq, false); + if (irq == IRQ_INVALID) { + pr_err("[%s] invalid irq num", __func__); + ret = -EINVAL; + } else { + if (request_irq_arch(irq) == false) { + pr_err("[%s] failed to request irq %u", + __func__, irq); + free_irq_num(irq); + ret = -EINVAL; + } else { + desc = &irq_desc_array[irq]; + spinlock_irqsave_obtain(&desc->lock, &rflags); + if (desc->action == NULL) { + desc->flags = flags; + desc->priv_data = priv_data; + desc->action = action_fn; + spinlock_irqrestore_release(&desc->lock, rflags); + + ret = (int32_t)irq; + } else { + spinlock_irqrestore_release(&desc->lock, rflags); + + ret = -EBUSY; + pr_err("%s: request irq(%u) failed, already requested", + __func__, irq); + } + } + } + + return ret; +} + +void free_irq(uint32_t irq) +{ + uint64_t rflags; + struct irq_desc *desc; + + if (irq < NR_IRQS) { + desc = &irq_desc_array[irq]; + + spinlock_irqsave_obtain(&desc->lock, &rflags); + desc->action = NULL; + desc->priv_data = NULL; + desc->flags = IRQF_NONE; + spinlock_irqrestore_release(&desc->lock, rflags); + + free_irq_arch(irq); + free_irq_num(irq); + } +} + +void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered) +{ + uint64_t rflags; + struct irq_desc *desc; + + if (irq < NR_IRQS) { + desc = &irq_desc_array[irq]; + spinlock_irqsave_obtain(&desc->lock, &rflags); + if (is_level_triggered) { + desc->flags |= IRQF_LEVEL; + } else { + desc->flags &= ~IRQF_LEVEL; + } + spinlock_irqrestore_release(&desc->lock, rflags); + } +} + +static inline void handle_irq(const struct irq_desc *desc) +{ + irq_action_t action = desc->action; + + pre_irq_arch(desc); + + eoi_irq_arch(desc); + + if (action != NULL) { + action(desc->irq, desc->priv_data); + } + + post_irq_arch(desc); +} + +void do_irq(const uint32_t irq) +{ + struct irq_desc *desc; + + if (irq < NR_IRQS) { + desc = &irq_desc_array[irq]; + per_cpu(irq_count, get_pcpu_id())[irq]++; + + /* XXX irq_alloc_bitmap is used lockless here */ + if (bitmap_test((uint16_t)(irq & 0x3FU), irq_alloc_bitmap + (irq >> 6U))) { + handle_irq(desc); + } + } + + do_softirq(); +} + +static void init_irq_descs(void) +{ + uint32_t i; + struct irq_desc *desc; + + for (i = 0U; i < NR_IRQS; i++) { + desc = &irq_desc_array[i]; + desc->irq = i; + spinlock_init(&desc->lock); + } + + init_irq_descs_arch(irq_desc_array); + + for (i = 0U; i < NR_IRQS; i++) { + desc = &irq_desc_array[i]; + if (irq_allocated_arch(desc)) { + bitmap_set_nolock((uint16_t)(desc->irq & 0x3FU), + irq_alloc_bitmap + (desc->irq >> 6U)); + } + } +} + +static void init_irqs(void) +{ + init_irq_descs(); + setup_irqs_arch(); + init_softirq(); +} + +void init_interrupt(uint16_t pcpu_id) +{ + init_interrupt_arch(pcpu_id); + + if (pcpu_id == BSP_CPU_ID) { + init_irqs(); + } + CPU_IRQ_ENABLE(); +} diff --git a/hypervisor/common/ptdev.c b/hypervisor/common/ptdev.c deleted file mode 100644 index 761f07fe3d..0000000000 --- a/hypervisor/common/ptdev.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define PTIRQ_ENTRY_HASHBITS 9U -#define PTIRQ_ENTRY_HASHSIZE (1U << PTIRQ_ENTRY_HASHBITS) - -#define PTIRQ_BITMAP_ARRAY_SIZE INT_DIV_ROUNDUP(CONFIG_MAX_PT_IRQ_ENTRIES, 64U) -struct ptirq_remapping_info ptirq_entries[CONFIG_MAX_PT_IRQ_ENTRIES]; -static uint64_t ptirq_entry_bitmaps[PTIRQ_BITMAP_ARRAY_SIZE]; -spinlock_t ptdev_lock = { .head = 0U, .tail = 0U, }; - -static struct ptirq_entry_head { - struct hlist_head list; -} ptirq_entry_heads[PTIRQ_ENTRY_HASHSIZE]; - -static inline uint16_t ptirq_alloc_entry_id(void) -{ - uint16_t id = (uint16_t)ffz64_ex(ptirq_entry_bitmaps, CONFIG_MAX_PT_IRQ_ENTRIES); - - while (id < CONFIG_MAX_PT_IRQ_ENTRIES) { - if (!bitmap_test_and_set_lock((id & 0x3FU), &ptirq_entry_bitmaps[id >> 6U])) { - break; - } - id = (uint16_t)ffz64_ex(ptirq_entry_bitmaps, CONFIG_MAX_PT_IRQ_ENTRIES); - } - - return (id < CONFIG_MAX_PT_IRQ_ENTRIES) ? id: INVALID_PTDEV_ENTRY_ID; -} - -struct ptirq_remapping_info *find_ptirq_entry(uint32_t intr_type, - const union source_id *sid, const struct acrn_vm *vm) -{ - struct hlist_node *p; - struct ptirq_remapping_info *n, *entry = NULL; - uint64_t key = hash64(sid->value, PTIRQ_ENTRY_HASHBITS); - struct ptirq_entry_head *b = &ptirq_entry_heads[key]; - - hlist_for_each(p, &b->list) { - if (vm == NULL) { - n = hlist_entry(p, struct ptirq_remapping_info, phys_link); - } else { - n = hlist_entry(p, struct ptirq_remapping_info, virt_link); - } - - if (is_entry_active(n)) { - if ((intr_type == n->intr_type) && - ((vm == NULL) ? - (sid->value == n->phys_sid.value) : - ((vm == n->vm) && (sid->value == n->virt_sid.value)))) { - entry = n; - break; - } - } - } - - return entry; -} - -static void ptirq_enqueue_softirq(struct ptirq_remapping_info *entry) -{ - uint64_t rflags; - - /* enqueue request in order, SOFTIRQ_PTDEV will pickup */ - CPU_INT_ALL_DISABLE(&rflags); - - /* avoid adding recursively */ - list_del(&entry->softirq_node); - /* TODO: assert if entry already in list */ - list_add_tail(&entry->softirq_node, &get_cpu_var(softirq_dev_entry_list)); - CPU_INT_ALL_RESTORE(rflags); - fire_softirq(SOFTIRQ_PTDEV); -} - -static void ptirq_intr_delay_callback(void *data) -{ - struct ptirq_remapping_info *entry = (struct ptirq_remapping_info *) data; - - ptirq_enqueue_softirq(entry); -} - -struct ptirq_remapping_info *ptirq_dequeue_softirq(uint16_t pcpu_id) -{ - uint64_t rflags; - struct ptirq_remapping_info *entry = NULL; - - CPU_INT_ALL_DISABLE(&rflags); - - while (!list_empty(&get_cpu_var(softirq_dev_entry_list))) { - entry = get_first_item(&per_cpu(softirq_dev_entry_list, pcpu_id), struct ptirq_remapping_info, softirq_node); - - list_del_init(&entry->softirq_node); - - /* if sos vm, just dequeue, if uos, check delay timer */ - if (is_sos_vm(entry->vm) || timer_expired(&entry->intr_delay_timer)) { - break; - } else { - /* add it into timer list; dequeue next one */ - (void)add_timer(&entry->intr_delay_timer); - entry = NULL; - } - } - - CPU_INT_ALL_RESTORE(rflags); - return entry; -} - -struct ptirq_remapping_info *ptirq_alloc_entry(struct acrn_vm *vm, uint32_t intr_type) -{ - struct ptirq_remapping_info *entry = NULL; - uint16_t ptirq_id = ptirq_alloc_entry_id(); - - if (ptirq_id < CONFIG_MAX_PT_IRQ_ENTRIES) { - entry = &ptirq_entries[ptirq_id]; - (void)memset((void *)entry, 0U, sizeof(struct ptirq_remapping_info)); - entry->ptdev_entry_id = ptirq_id; - entry->intr_type = intr_type; - entry->vm = vm; - entry->intr_count = 0UL; - entry->irte_idx = INVALID_IRTE_ID; - - INIT_LIST_HEAD(&entry->softirq_node); - - initialize_timer(&entry->intr_delay_timer, ptirq_intr_delay_callback, entry, 0UL, 0, 0UL); - - entry->active = false; - } else { - pr_err("Alloc ptdev irq entry failed"); - } - - return entry; -} - -void ptirq_release_entry(struct ptirq_remapping_info *entry) -{ - uint64_t rflags; - - CPU_INT_ALL_DISABLE(&rflags); - list_del_init(&entry->softirq_node); - del_timer(&entry->intr_delay_timer); - CPU_INT_ALL_RESTORE(rflags); - - bitmap_clear_lock((entry->ptdev_entry_id) & 0x3FU, &ptirq_entry_bitmaps[entry->ptdev_entry_id >> 6U]); - - (void)memset((void *)entry, 0U, sizeof(struct ptirq_remapping_info)); -} - -/* interrupt context */ -static void ptirq_interrupt_handler(__unused uint32_t irq, void *data) -{ - struct ptirq_remapping_info *entry = (struct ptirq_remapping_info *) data; - bool to_enqueue = true; - - /* - * "interrupt storm" detection & delay intr injection just for UOS - * pass-thru devices, collect its data and delay injection if needed - */ - if (!is_sos_vm(entry->vm)) { - entry->intr_count++; - - /* if delta > 0, set the delay TSC, dequeue to handle */ - if (entry->vm->intr_inject_delay_delta > 0UL) { - - /* if the timer started (entry is in timer-list), not need enqueue again */ - if (timer_is_started(&entry->intr_delay_timer)) { - to_enqueue = false; - } else { - entry->intr_delay_timer.fire_tsc = rdtsc() + entry->vm->intr_inject_delay_delta; - } - } else { - entry->intr_delay_timer.fire_tsc = 0UL; - } - } - - if (to_enqueue) { - ptirq_enqueue_softirq(entry); - } -} - -/* active intr with irq registering */ -int32_t ptirq_activate_entry(struct ptirq_remapping_info *entry, uint32_t phys_irq) -{ - int32_t retval; - uint64_t key; - - /* register and allocate host vector/irq */ - retval = request_irq(phys_irq, ptirq_interrupt_handler, (void *)entry, IRQF_PT); - - if (retval < 0) { - pr_err("request irq failed, please check!, phys-irq=%d", phys_irq); - } else { - entry->allocated_pirq = (uint32_t)retval; - entry->active = true; - - key = hash64(entry->phys_sid.value, PTIRQ_ENTRY_HASHBITS); - hlist_add_head(&entry->phys_link, &(ptirq_entry_heads[key].list)); - key = hash64(entry->virt_sid.value, PTIRQ_ENTRY_HASHBITS); - hlist_add_head(&entry->virt_link, &(ptirq_entry_heads[key].list)); - } - - return retval; -} - -void ptirq_deactivate_entry(struct ptirq_remapping_info *entry) -{ - hlist_del(&entry->phys_link); - hlist_del(&entry->virt_link); - entry->active = false; - free_irq(entry->allocated_pirq); -} - -void ptdev_init(void) -{ - if (get_pcpu_id() == BSP_CPU_ID) { - register_softirq(SOFTIRQ_PTDEV, ptirq_softirq); - } - INIT_LIST_HEAD(&get_cpu_var(softirq_dev_entry_list)); -} - -void ptdev_release_all_entries(const struct acrn_vm *vm) -{ - struct ptirq_remapping_info *entry; - uint16_t idx; - - /* VM already down */ - for (idx = 0U; idx < CONFIG_MAX_PT_IRQ_ENTRIES; idx++) { - entry = &ptirq_entries[idx]; - if ((entry->vm == vm) && is_entry_active(entry)) { - spinlock_obtain(&ptdev_lock); - if (entry->release_cb != NULL) { - entry->release_cb(entry); - } - ptirq_deactivate_entry(entry); - ptirq_release_entry(entry); - spinlock_release(&ptdev_lock); - } - } - -} - -uint32_t ptirq_get_intr_data(const struct acrn_vm *target_vm, uint64_t *buffer, uint32_t buffer_cnt) -{ - uint32_t index = 0U; - uint16_t i; - struct ptirq_remapping_info *entry; - - for (i = 0U; i < CONFIG_MAX_PT_IRQ_ENTRIES; i++) { - entry = &ptirq_entries[i]; - if (!is_entry_active(entry)) { - continue; - } - if (entry->vm == target_vm) { - buffer[index] = entry->allocated_pirq; - buffer[index + 1U] = entry->intr_count; - - index += 2U; - if (index > (buffer_cnt - 2U)) { - break; - } - } - } - - return index; -} diff --git a/hypervisor/common/ptintr.c b/hypervisor/common/ptintr.c new file mode 100644 index 0000000000..54eb3bd3fc --- /dev/null +++ b/hypervisor/common/ptintr.c @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DBG_LEVEL_PTINTR 6U + +#define PTINTR_BITMAP_ARRAY_SIZE INT_DIV_ROUNDUP(CONFIG_MAX_PT_IRQ_ENTRIES, 64U) +#define PTINTR_BITMAP_SIZE (PTINTR_BITMAP_ARRAY_SIZE << 6U) +#define PTINTR_ENTRY_HASHBITS 9U +#define PTINTR_ENTRY_HASHSIZE (1U << PTINTR_ENTRY_HASHBITS) + +struct ptintr ptintr_entries[CONFIG_MAX_PT_IRQ_ENTRIES]; +static uint64_t ptintr_entry_bitmaps[PTINTR_BITMAP_ARRAY_SIZE]; +static spinlock_t ptintr_lock; + +static struct ptintr_entry_head { + struct hlist_head list; +} ptintr_entry_heads[PTINTR_ENTRY_HASHSIZE]; + +static inline uint16_t alloc_ptintr_id(void) +{ + uint16_t id = (uint16_t)ffz64_ex(ptintr_entry_bitmaps, PTINTR_BITMAP_SIZE); + + if (id < ARRAY_SIZE(ptintr_entries)) { + bitmap_set_nolock(id & 0x3FU, &ptintr_entry_bitmaps[id >> 6U]); + } else { + id = INVALID_PTDEV_ENTRY_ID; + } + + return id; +} + +static void ptintr_free(struct ptintr *intr) +{ + intr->active = false; + ptirq_free(intr->irq); + hlist_del(&intr->phys_link); + hlist_del(&intr->virt_link); + bitmap_clear_nolock(intr->id & 0x3FU, + &ptintr_entry_bitmaps[intr->id >> 6U]); +} + +static struct ptintr *ptintr_alloc(struct acrn_vm *vm, uint32_t intr_type, + union source_id *phys_sid, union source_id *virt_sid) +{ + struct ptintr *intr = NULL; + uint16_t id = alloc_ptintr_id(); + uint64_t key; + + if (id < ARRAY_SIZE(ptintr_entries)) { + intr = &ptintr_entries[id]; + (void)memset((void *)intr, 0U, sizeof(*intr)); + intr->id = id; + intr->vm = vm; + intr->intr_type = intr_type; + intr->phys_sid = *phys_sid; + intr->virt_sid = *virt_sid; + + key = hash64(intr->phys_sid.value, PTINTR_ENTRY_HASHBITS); + hlist_add_head(&intr->phys_link, &(ptintr_entry_heads[key].list)); + key = hash64(intr->virt_sid.value, PTINTR_ENTRY_HASHBITS); + hlist_add_head(&intr->virt_link, &(ptintr_entry_heads[key].list)); + + if (ptirq_request(&intr->irq, vm, intr_type, phys_sid, virt_sid) < 0) { + ptintr_free(intr); + } else { + intr->active = true; + } + } else { + pr_err("ptintr alloc failed"); + } + + return intr; +} + +/* ptintr_lock must be held */ +static struct ptintr *ptintr_find(uint32_t intr_type, + const union source_id *sid, const struct acrn_vm *vm) +{ + struct hlist_node *p; + struct ptintr *n, *intr = NULL; + uint64_t key = hash64(sid->value, PTINTR_ENTRY_HASHBITS); + struct ptintr_entry_head *b = &ptintr_entry_heads[key]; + + hlist_for_each(p, &b->list) { + /* FIXME bug */ + if (vm == NULL) { + n = hlist_entry(p, struct ptintr, phys_link); + } else { + n = hlist_entry(p, struct ptintr, virt_link); + } + + if (n->active) { + if ((intr_type == n->intr_type) && + ((vm == NULL) ? + (sid->value == n->phys_sid.value) : + ((vm == n->vm) && (sid->value == n->virt_sid.value)))) { + intr = n; + break; + } + } + } + + return intr; +} + +/* + * add msix entry for a vm, based on msi id (phys_bdf+msix_index) + * - if the entry not be added by any vm, allocate it + * - if the entry already be added by sos_vm, then change the owner to current vm + * - if the entry already be added by other vm, return NULL + */ +static struct ptintr *add_msix_entry(struct acrn_vm *vm, + uint16_t virt_bdf, uint16_t phys_bdf, uint32_t entry_nr) +{ + struct ptintr *intr; + DEFINE_MSI_SID(phys_sid, phys_bdf, entry_nr); + DEFINE_MSI_SID(virt_sid, virt_bdf, entry_nr); + + intr = ptintr_find(PTDEV_INTR_MSI, &phys_sid, NULL); + + if (intr == NULL) { + if (ptintr_find(PTDEV_INTR_MSI, &virt_sid, vm) == NULL) { + intr = ptintr_alloc(vm, PTDEV_INTR_MSI, + &phys_sid, &virt_sid); + } else { + pr_err("MSIX re-add VM%u vbdf%x", vm->vm_id, virt_bdf); + } + + if (intr != NULL) { + dev_dbg(DBG_LEVEL_PTINTR, + "VM%u MSIX add vector mapping vbdf%x:pbdf%x idx=%d", + vm->vm_id, virt_bdf, phys_bdf, entry_nr); + } + } + + return intr; +} + +/* + * Main entry for PCI device assignment with MSI and MSI-X + * MSI can up to 8 vectors and MSI-X can up to 1024 Vectors + * We use entry_nr to indicate coming vectors + * entry_nr = 0 means first vector + * user must provide bdf and entry_nr + */ +static int32_t add_msix_remapping(struct acrn_vm *vm, struct ptintr_add_msix *args) +{ + struct ptintr *intr; + int32_t ret = 0; + + /* + * adds the mapping entries at runtime, if the + * entry already be held by others, return error. + */ + spinlock_obtain(&ptintr_lock); + intr = add_msix_entry(vm, args->virt_bdf, args->phys_bdf, args->entry_nr); + spinlock_release(&ptintr_lock); + + if (intr == NULL) { + pr_err("%s: add msix remapping failed", __func__); + ret = -ENODEV; + } + + return ret; +} + +/* + * add intx entry for a vm, based on intx id (phys_pin) + * - if the entry not be added by any vm, allocate it + * - if the entry already be added by sos_vm, then change the owner to current vm + * - if the entry already be added by other vm, return NULL + */ +static struct ptintr *add_intx_entry(struct acrn_vm *vm, uint32_t virt_gsi, + uint32_t virt_ctlr, uint32_t phys_gsi, uint32_t phys_ctlr) +{ + struct ptintr *intr = NULL; + DEFINE_INTX_SID(phys_sid, phys_gsi, phys_ctlr); + DEFINE_INTX_SID(virt_sid, virt_gsi, virt_ctlr); + + intr = ptintr_find(PTDEV_INTR_INTX, &phys_sid, NULL); + + if (intr == NULL) { + if (ptintr_find(PTDEV_INTR_INTX, &virt_sid, vm) == NULL) { + intr = ptintr_alloc(vm, PTDEV_INTR_INTX, + &phys_sid, &virt_sid); + } else { + pr_err("INTx re-add VM%u vpin %d", vm->vm_id, virt_gsi); + } + } else if (intr->vm != vm) { + if (is_sos_vm(intr->vm)) { + intr->vm = vm; + intr->virt_sid = virt_sid; + /* FIXME re-insert */ + ptirq_set_polarity(intr->irq, 0U); + } else { + pr_err("INTx gsi%d already in vm%u with vgsi%d, " + "not able to add into vm%u with vgsi%d", + phys_gsi, intr->vm->vm_id, intr->virt_sid.intx_id.gsi, + vm->vm_id, virt_gsi); + intr = NULL; + } + } else { + /* + * The mapping has already been added to the VM. No action + * required. + */ + } + + /* + * intr is either created or transferred from SOS VM to Post-launched VM + */ + if (intr != NULL) { + dev_dbg(DBG_LEVEL_PTINTR, "VM%u INTX add pin mapping vgsi%d:pgsi%d", + intr->vm->vm_id, virt_gsi, phys_gsi); + } + + return intr; +} + +/* + * Main entry for PCI/Legacy device assignment with INTx + */ +static int32_t add_intx_remapping(struct acrn_vm *vm, struct ptintr_add_intx *args) +{ + int32_t ret = 0; + struct ptintr *intr = NULL; + DEFINE_INTX_SID(virt_sid, args->virt_gsi, args->virt_ctlr); + + /* + * Device Model should pre-hold the mapping entries by calling + * ptintr_add for UOS. + */ + + spinlock_obtain(&ptintr_lock); + + /* no remap for vuart intx */ + if (!is_vuart_intx(vm, virt_sid.intx_id.gsi)) { + /* query if we have virt to phys mapping */ + if (ptintr_find(PTDEV_INTR_INTX, &virt_sid, vm) == NULL) { + ret = ptintr_add_intx_arch(vm, &virt_sid); + } + } else { + ret = -EINVAL; + } + + if (ret == -ENODEV) { + intr = add_intx_entry(vm, args->virt_gsi, args->virt_ctlr, + args->phys_gsi, args->phys_ctlr); + + if (intr == NULL) { + pr_err("%s: add intx remapping failed", __func__); + } else { + ret = 0; + } + } else if (ret == -EACCES) { + /* FIXME re-insert */ + ret = 0; + } + spinlock_release(&ptintr_lock); + + return ret; +} + +int32_t ptintr_add(struct acrn_vm *vm, struct ptintr_add_args *args) +{ + int32_t ret = -EINVAL; + + switch (args->intr_type) { + case PTDEV_INTR_MSI: + ret = add_msix_remapping(vm, &args->msix); + break; + case PTDEV_INTR_INTX: + ret = add_intx_remapping(vm, &args->intx); + break; + default: + pr_fatal("Unsupported intr_type %u", args->intr_type); + break; + } + + return ret; +} + +static int32_t remap_msix(struct acrn_vm *vm, struct ptintr_remap_msix *args) +{ + int32_t ret = -EINVAL; + struct ptintr *intr; + DEFINE_MSI_SID(virt_sid, args->virt_bdf, args->entry_nr); + + spinlock_obtain(&ptintr_lock); + intr = ptintr_find(PTDEV_INTR_MSI, &virt_sid, vm); + + if (intr != NULL) { + ptirq_set_vmsi(intr->irq, args->info); + ret = ptintr_remap_msix_arch(intr, args); /* pmsi is handled by arch */ + + if (ret == 0) { + *args->info = intr->pmsi; + + if (args->remap_cb != NULL) { + ret = args->remap_cb(args->remap_arg); + } + } + } + spinlock_release(&ptintr_lock); + + return ret; +} + +static int32_t remap_intx(struct acrn_vm *vm, struct ptintr_remap_intx *args) +{ + int32_t ret = -EINVAL; + struct ptintr *intr; + DEFINE_INTX_SID(virt_sid, args->virt_gsi, args->virt_ctlr); + + spinlock_obtain(&ptintr_lock); + intr = ptintr_find(PTDEV_INTR_INTX, &virt_sid, vm); + + if (intr != NULL) { + ret = ptintr_remap_intx_arch(intr, args); + } + spinlock_release(&ptintr_lock); + + return ret; +} + +int32_t ptintr_remap(struct acrn_vm *vm, struct ptintr_remap_args *args) +{ + int32_t ret = -EINVAL; + + switch (args->intr_type) { + case PTDEV_INTR_MSI: + ret = remap_msix(vm, &args->msix); + break; + case PTDEV_INTR_INTX: + ret = remap_intx(vm, &args->intx); + break; + default: + pr_fatal("Unsupported intr_type %u", args->intr_type); + break; + } + + return ret; +} + +static void remove_and_unmap_msix_entry(struct ptintr *intr) +{ + dev_dbg(DBG_LEVEL_PTINTR, + "VM%u MSIX remove vector mapping vbdf-pbdf:0x%x-0x%x idx=%d", + intr->vm->vm_id, intr->virt_sid.msi_id.bdf, + intr->phys_sid.msi_id.bdf, intr->phys_sid.msi_id.entry_nr); + + ptintr_remove_msix_arch(intr); + ptintr_free(intr); +} + +/* deactivate & remove mapping entry of vbdf:entry_nr for vm */ +static void remove_msix_remapping(const struct acrn_vm *vm, struct ptintr_rmv_msix *args) +{ + struct ptintr *intr; + DEFINE_MSI_SID(phys_sid, args->phys_bdf, args->entry_nr); + + spinlock_obtain(&ptintr_lock); + intr = ptintr_find(PTDEV_INTR_MSI, &phys_sid, NULL); + + if ((intr != NULL) && (intr->vm == vm)) { + remove_and_unmap_msix_entry(intr); + } + spinlock_release(&ptintr_lock); +} + +static void remove_and_unmap_intx_entry(struct ptintr *intr) +{ + dev_dbg(DBG_LEVEL_PTINTR, + "remove intx intr: vgsi_ctlr=%u vgsi=%u pgsi=%u from VM%u", + intr->virt_sid.intx_id.ctlr, intr->virt_sid.intx_id.gsi, + intr->phys_sid.intx_id.gsi, intr->vm->vm_id); + + ptintr_remove_intx_arch(intr); + ptintr_free(intr); +} + +/* deactivate & remove mapping entry of vpin for vm */ +static void remove_intx_remapping(const struct acrn_vm *vm, struct ptintr_rmv_intx *args) +{ + struct ptintr *intr; + DEFINE_INTX_SID(virt_sid, args->virt_gsi, args->virt_ctlr); + + spinlock_obtain(&ptintr_lock); + intr = ptintr_find(PTDEV_INTR_INTX, &virt_sid, vm); + + if (intr != NULL) { + remove_and_unmap_intx_entry(intr); + } + spinlock_release(&ptintr_lock); +} + +void ptintr_remove_and_unmap(struct acrn_vm *vm, struct ptintr_rmv_args *args) +{ + switch (args->intr_type) { + case PTDEV_INTR_MSI: + remove_msix_remapping(vm, &args->msix); + break; + case PTDEV_INTR_INTX: + remove_intx_remapping(vm, &args->intx); + break; + default: + pr_fatal("Unsupported intr_type %u", args->intr_type); + break; + } +} + +void ptintr_remove_and_unmap_vm(const struct acrn_vm *vm) +{ + uint16_t i; + struct ptintr *intr; + + spinlock_obtain(&ptintr_lock); + + /* VM is already down */ + for (i = 0U; i < ARRAY_SIZE(ptintr_entries); i++) { + intr = &ptintr_entries[i]; + + if (intr->active && (intr->vm == vm)) { + if (intr->intr_type == PTDEV_INTR_MSI) { + remove_and_unmap_msix_entry(intr); + } else { + remove_and_unmap_intx_entry(intr); + } + } + } + spinlock_release(&ptintr_lock); +} + +void ptintr_intx_ack(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_ctlr) +{ + struct ptintr *intr; + DEFINE_INTX_SID(virt_sid, virt_gsi, vgsi_ctlr); + + spinlock_obtain(&ptintr_lock); + intr = ptintr_find(PTDEV_INTR_INTX, &virt_sid, vm); + + if ((intr != NULL) && intr->active) { + ptirq_intx_ack_arch(intr->irq); + } + spinlock_release(&ptintr_lock); +} + +uint32_t ptintr_get_intr_data(const struct acrn_vm *target_vm, uint64_t *buffer, uint32_t buffer_cnt) +{ + uint16_t i; + uint32_t pos = 0U; + struct ptintr *intr; + + spinlock_obtain(&ptintr_lock); + + for (i = 0U; i < ARRAY_SIZE(ptintr_entries); i++) { + intr = &ptintr_entries[i]; + + if (intr->active && (intr->vm == target_vm)) { + if (ptirq_get_intr_data( + intr->irq, buffer, &pos, buffer_cnt) < 0) { + break; + } + } + } + spinlock_release(&ptintr_lock); + + return pos; +} + +void ptintr_init(void) +{ + if (get_pcpu_id() == BSP_CPU_ID) { + spinlock_init(&ptintr_lock); + } + ptintr_init_arch(ptintr_find); + ptirq_init(); +} diff --git a/hypervisor/common/ptirq.c b/hypervisor/common/ptirq.c new file mode 100644 index 0000000000..1c7f30c679 --- /dev/null +++ b/hypervisor/common/ptirq.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTIRQ_BITMAP_ARRAY_SIZE INT_DIV_ROUNDUP(CONFIG_MAX_PT_IRQ_ENTRIES, 64U) +#define PTIRQ_BITMAP_SIZE (PTIRQ_BITMAP_ARRAY_SIZE << 6U) + +static struct ptirq ptirq_entries[CONFIG_MAX_PT_IRQ_ENTRIES]; +static uint64_t ptirq_entry_bitmaps[PTIRQ_BITMAP_ARRAY_SIZE]; + +static inline uint16_t alloc_ptirq_id(void) +{ + uint16_t id = (uint16_t)ffz64_ex(ptirq_entry_bitmaps, PTIRQ_BITMAP_SIZE); + + if (id < ARRAY_SIZE(ptirq_entries)) { + bitmap_set_nolock(id & 0x3FU, &ptirq_entry_bitmaps[id >> 6U]); + } else { + id = INVALID_PTDEV_ENTRY_ID; + } + + return id; +} + +static inline void free_ptirq_id(uint16_t id) +{ + if (id < ARRAY_SIZE(ptirq_entries)) { + bitmap_clear_nolock(id & 0x3FU, &ptirq_entry_bitmaps[id >> 6U]); + } +} + +static void enq_softirq(struct ptirq *irq) +{ + uint64_t rflags; + + /* enqueue request in order, SOFTIRQ_PTDEV will pick up */ + CPU_INT_ALL_DISABLE(&rflags); + + /* avoid adding recursively */ + list_del(&irq->softirq_node); + /* TODO: assert if irq already in list */ + list_add_tail(&irq->softirq_node, &get_cpu_var(softirq_dev_entry_list)); + CPU_INT_ALL_RESTORE(rflags); + fire_softirq(SOFTIRQ_PTDEV); +} + +static void ptirq_intr_delay_callback(void *data) +{ + struct ptirq *irq = (struct ptirq *)data; + + enq_softirq(irq); +} + +/* interrupt context */ +static void ptirq_interrupt_handler(__unused uint32_t irqn, void *data) +{ + struct ptirq *irq = (struct ptirq *)data; + bool to_enqueue = true; + + /* + * "interrupt storm" detection & delay intr injection just for UOS + * pass-thru devices, collect its data and delay injection if needed + */ + if (!is_sos_vm(irq->vm)) { + irq->intr_count++; + + /* if delta > 0, set the delay TSC, dequeue to handle */ + if (irq->vm->intr_inject_delay_delta > 0UL) { + + /* if the timer started (irq is in timer-list), not need enqueue again */ + if (timer_is_started(&irq->intr_delay_timer)) { + to_enqueue = false; + } else { + irq->intr_delay_timer.timeout = + get_cpu_cycles() + irq->vm->intr_inject_delay_delta; + } + } else { + irq->intr_delay_timer.timeout = 0UL; + } + } + + if (to_enqueue) { + enq_softirq(irq); + } +} + +static struct ptirq *deq_softirq(uint16_t pcpu_id) +{ + uint64_t rflags; + struct ptirq *irq = NULL; + + CPU_INT_ALL_DISABLE(&rflags); + + while (!list_empty(&get_cpu_var(softirq_dev_entry_list))) { + irq = get_first_item(&per_cpu(softirq_dev_entry_list, pcpu_id), + struct ptirq, softirq_node); + + list_del_init(&irq->softirq_node); + + /* if sos vm, just dequeue, if uos, check delay timer */ + if (is_sos_vm(irq->vm) || + timer_expired(&irq->intr_delay_timer, get_cpu_cycles(), NULL)) { + break; + } else { + /* add it into timer list; dequeue next one */ + (void)add_timer(&irq->intr_delay_timer); + irq = NULL; + } + } + + CPU_INT_ALL_RESTORE(rflags); + return irq; +} + +static void ptirq_softirq(uint16_t pcpu_id) +{ + struct ptirq *irq; + + for (irq = deq_softirq(pcpu_id); irq != NULL; irq = deq_softirq(pcpu_id)) { + /* only service active irqs */ + if (irq->active) { + ptirq_softirq_arch(irq); + } + } +} + +void ptirq_set_vmsi(struct ptirq *irq, struct msi_info *vmsi) +{ + if (irq->active && (irq->intr_type == PTDEV_INTR_MSI)) { + irq->vmsi = *vmsi; + } +} + +void ptirq_set_polarity(struct ptirq *irq, uint32_t polarity) +{ + if (irq->active) { + irq->polarity = polarity; + } +} + +uint32_t ptirq_get_polarity(struct ptirq *irq) +{ + return irq->active ? irq->polarity : 0U; +} + +uint32_t ptirq_get_irq(struct ptirq *irq) +{ + return irq->active ? irq->allocated_pirq : IRQ_INVALID; +} + +/* activate intr with irq registering */ +int32_t ptirq_request(struct ptirq **irq, struct acrn_vm *vm, uint32_t intr_type, + union source_id *phys_sid, union source_id *virt_sid) +{ + int32_t retval = -EINVAL; + uint16_t id = alloc_ptirq_id(); + uint32_t phys_irq; + struct ptirq *entry; + + if (id < ARRAY_SIZE(ptirq_entries)) { + entry = &ptirq_entries[id]; + (void)memset((void *)entry, 0U, sizeof(*entry)); + entry->id = id; + entry->vm = vm; + entry->intr_type = intr_type; + entry->virt_sid = *virt_sid; + + phys_irq = ptirq_get_irq_arch(intr_type, phys_sid); + + INIT_LIST_HEAD(&entry->softirq_node); + initialize_timer(&entry->intr_delay_timer, ptirq_intr_delay_callback, + entry, 0UL, 0UL); + + /* register and allocate host irq */ + retval = request_irq(phys_irq, ptirq_interrupt_handler, + (void *)entry, IRQF_PT); + + if (retval < 0) { + free_ptirq_id(id); + pr_err("request irq failed, please check!, phys-irq=%u", phys_irq); + } else { + entry->allocated_pirq = (uint32_t)retval; + entry->active = true; + *irq = entry; + } + } else { + pr_err("ptirq alloc failed"); + } + + return retval; +} + +void ptirq_free(struct ptirq *irq) +{ + uint64_t rflags; + + if ((irq != NULL) && irq->active) { + irq->active = false; + free_irq(irq->allocated_pirq); + + CPU_INT_ALL_DISABLE(&rflags); + list_del(&irq->softirq_node); + del_timer(&irq->intr_delay_timer); + CPU_INT_ALL_RESTORE(rflags); + free_ptirq_id(irq->id); + } +} + +int32_t ptirq_get_intr_data(struct ptirq *irq, uint64_t *buffer, + uint32_t *pos, uint32_t buffer_cnt) +{ + int32_t written = 0U; + + if (irq->active) { + if ((*pos + 2U) > buffer_cnt) { + written = -1; + } else { + buffer[*pos] = irq->allocated_pirq; + buffer[*pos + 1U] = irq->intr_count; + *pos += 2U; + written += 2U; + } + } + + return written; +} + +void ptirq_init(void) +{ + if (get_pcpu_id() == BSP_CPU_ID) { + register_softirq(SOFTIRQ_PTDEV, ptirq_softirq); + } + INIT_LIST_HEAD(&get_cpu_var(softirq_dev_entry_list)); +} diff --git a/hypervisor/common/sched_bvt.c b/hypervisor/common/sched_bvt.c index fc75b916e2..756225fcc3 100644 --- a/hypervisor/common/sched_bvt.c +++ b/hypervisor/common/sched_bvt.c @@ -5,8 +5,9 @@ */ #include -#include +#include #include +#include #define BVT_MCU_MS 1U /* context switch allowance */ @@ -158,7 +159,7 @@ static int sched_bvt_init(struct sched_control *ctl) /* The tick_timer is periodically */ initialize_timer(&bvt_ctl->tick_timer, sched_tick_handler, ctl, - rdtsc() + tick_period, TICK_MODE_PERIODIC, tick_period); + get_cpu_cycles() + tick_period, tick_period); if (add_timer(&bvt_ctl->tick_timer) < 0) { pr_err("Failed to add schedule tick timer!"); @@ -200,14 +201,14 @@ static uint64_t p2v(uint64_t phy_time, uint64_t ratio) static void update_vt(struct thread_object *obj) { struct sched_bvt_data *data; - uint64_t now_tsc = rdtsc(); + uint64_t now = get_cpu_cycles(); uint64_t v_delta, delta_mcu = 0U; data = (struct sched_bvt_data *)obj->data; /* update current thread's avt and evt */ - if (now_tsc > data->start_tsc) { - v_delta = p2v(now_tsc - data->start_tsc, data->vt_ratio) + data->residual; + if (now > data->start_tsc) { + v_delta = p2v(now - data->start_tsc, data->vt_ratio) + data->residual; delta_mcu = (uint64_t)(v_delta / data->mcu); data->residual = v_delta % data->mcu; } @@ -229,7 +230,7 @@ static struct thread_object *sched_bvt_pick_next(struct sched_control *ctl) struct list_head *first, *sec; struct thread_object *next = NULL; struct thread_object *current = ctl->curr_obj; - uint64_t now_tsc = rdtsc(); + uint64_t now = get_cpu_cycles(); uint64_t delta_mcu = 0U; if (!is_idle_thread(current)) { @@ -260,7 +261,7 @@ static struct thread_object *sched_bvt_pick_next(struct sched_control *ctl) } else { first_data->run_countdown = UINT64_MAX; } - first_data->start_tsc = now_tsc; + first_data->start_tsc = now; next = first_obj; } else { next = &get_cpu_var(idle); diff --git a/hypervisor/common/sched_iorr.c b/hypervisor/common/sched_iorr.c index ad98b4e4c0..5ba6389558 100644 --- a/hypervisor/common/sched_iorr.c +++ b/hypervisor/common/sched_iorr.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #define CONFIG_SLICE_MS 10UL @@ -77,7 +77,7 @@ static void sched_tick_handler(void *param) struct sched_iorr_data *data; struct thread_object *current; uint16_t pcpu_id = get_pcpu_id(); - uint64_t now = rdtsc(); + uint64_t now = get_cpu_cycles(); uint64_t rflags; obtain_schedule_lock(pcpu_id, &rflags); @@ -116,7 +116,7 @@ int sched_iorr_init(struct sched_control *ctl) /* The tick_timer is periodically */ initialize_timer(&iorr_ctl->tick_timer, sched_tick_handler, ctl, - rdtsc() + tick_period, TICK_MODE_PERIODIC, tick_period); + get_cpu_cycles() + tick_period, tick_period); if (add_timer(&iorr_ctl->tick_timer) < 0) { pr_err("Failed to add schedule tick timer!"); @@ -146,7 +146,7 @@ static struct thread_object *sched_iorr_pick_next(struct sched_control *ctl) struct thread_object *next = NULL; struct thread_object *current = NULL; struct sched_iorr_data *data; - uint64_t now = rdtsc(); + uint64_t now = get_cpu_cycles(); current = ctl->curr_obj; data = (struct sched_iorr_data *)current->data; diff --git a/hypervisor/common/sched_noop.c b/hypervisor/common/sched_noop.c index 8e9edbfc7b..659df9d360 100644 --- a/hypervisor/common/sched_noop.c +++ b/hypervisor/common/sched_noop.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include #include static int32_t sched_noop_init(struct sched_control *ctl) diff --git a/hypervisor/common/schedule.c b/hypervisor/common/schedule.c index 2986718be5..3c1812173a 100644 --- a/hypervisor/common/schedule.c +++ b/hypervisor/common/schedule.c @@ -6,10 +6,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/hypervisor/common/softirq.c b/hypervisor/common/softirq.c index aec994fed6..dfcd066df3 100644 --- a/hypervisor/common/softirq.c +++ b/hypervisor/common/softirq.c @@ -5,9 +5,9 @@ */ #include -#include -#include -#include +#include +#include +#include #include static softirq_handler softirq_handlers[NR_SOFTIRQS]; diff --git a/hypervisor/common/timer.c b/hypervisor/common/timer.c new file mode 100644 index 0000000000..2a5c11af9c --- /dev/null +++ b/hypervisor/common/timer.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_TIMER_ACTIONS 32U +#define MIN_TIMER_PERIOD_US 500U + +bool timer_expired(const struct hv_timer *timer, uint64_t now, uint64_t *delta) +{ + bool ret; + uint64_t delt = 0UL; + + if ((timer->timeout == 0UL) || (now >= timer->timeout)) { + ret = true; + } else { + ret = false; + delt = timer->timeout - now; + } + + if (delta != NULL) { + *delta = delt; + } + + return ret; +} + +bool timer_is_started(const struct hv_timer *timer) +{ + return (!list_empty(&timer->node)); +} + +static void run_timer(struct hv_timer *timer) +{ + /* deadline = 0 means stop timer, we should skip */ + if ((timer->func != NULL) && (timer->timeout != 0UL)) { + timer->func(timer->priv_data); + } + + TRACE_2L(TRACE_TIMER_ACTION_PCKUP, timer->timeout, 0UL); +} + +static inline void update_physical_timer(struct per_cpu_timers *cpu_timer) +{ + struct hv_timer *timer = NULL; + + /* find the next event timer */ + if (!list_empty(&cpu_timer->timer_list)) { + timer = container_of((&cpu_timer->timer_list)->next, + struct hv_timer, node); + + /* it is okay to program a expired time */ + set_hw_timeout(timer->timeout); + } +} + +/* + * return true if we add the timer on the timer_list head + */ +static bool local_add_timer(struct per_cpu_timers *cpu_timer, + struct hv_timer *timer) +{ + struct list_head *pos, *prev; + struct hv_timer *tmp; + uint64_t tsc = timer->timeout; + + prev = &cpu_timer->timer_list; + list_for_each(pos, &cpu_timer->timer_list) { + tmp = container_of(pos, struct hv_timer, node); + if (tmp->timeout < tsc) { + prev = &tmp->node; + } + else { + break; + } + } + + list_add(&timer->node, prev); + + return (prev == &cpu_timer->timer_list); +} + +int32_t add_timer(struct hv_timer *timer) +{ + struct per_cpu_timers *cpu_timer; + uint16_t pcpu_id; + int32_t ret = 0; + uint64_t rflags; + + if ((timer == NULL) || (timer->func == NULL) || (timer->timeout == 0UL)) { + ret = -EINVAL; + } else { + ASSERT(list_empty(&timer->node), "add timer again!\n"); + + /* limit minimal periodic timer cycle period */ + if (timer->mode == TICK_MODE_PERIODIC) { + timer->period_in_cycle = max(timer->period_in_cycle, us_to_cycles(MIN_TIMER_PERIOD_US)); + } + + pcpu_id = get_pcpu_id(); + cpu_timer = &per_cpu(cpu_timers, pcpu_id); + + CPU_INT_ALL_DISABLE(&rflags); + /* update the physical timer if we're on the timer_list head */ + if (local_add_timer(cpu_timer, timer)) { + update_physical_timer(cpu_timer); + } + CPU_INT_ALL_RESTORE(rflags); + + TRACE_2L(TRACE_TIMER_ACTION_ADDED, timer->timeout, 0UL); + } + + return ret; + +} + +void del_timer(struct hv_timer *timer) +{ + uint64_t rflags; + + CPU_INT_ALL_DISABLE(&rflags); + if ((timer != NULL) && !list_empty(&timer->node)) { + list_del_init(&timer->node); + } + CPU_INT_ALL_RESTORE(rflags); +} + +static void init_percpu_timer(uint16_t pcpu_id) +{ + struct per_cpu_timers *cpu_timer; + + cpu_timer = &per_cpu(cpu_timers, pcpu_id); + INIT_LIST_HEAD(&cpu_timer->timer_list); +} + +static void timer_softirq(uint16_t pcpu_id) +{ + struct per_cpu_timers *cpu_timer; + struct hv_timer *timer; + struct list_head *pos, *n; + uint32_t tries = MAX_TIMER_ACTIONS; + uint64_t current_timecnt = get_cpu_cycles(); + + /* handle passed timer */ + cpu_timer = &per_cpu(cpu_timers, pcpu_id); + + /* This is to make sure we are not blocked due to delay inside func() + * force to exit irq handler after we serviced >31 timers + * caller used to local_add_timer() for periodic timer, if there is a delay + * inside func(), it will infinitely loop here, because new added timer + * already passed due to previously func()'s delay. + */ + list_for_each_safe(pos, n, &cpu_timer->timer_list) { + timer = container_of(pos, struct hv_timer, node); + /* timer expried */ + tries--; + if ((timer->timeout <= current_timecnt) && (tries != 0U)) { + del_timer(timer); + + run_timer(timer); + + if (timer->mode == TICK_MODE_PERIODIC) { + /* update periodic timer fire tsc */ + timer->timeout += timer->period_in_cycle; + (void)local_add_timer(cpu_timer, timer); + } else { + timer->timeout = 0UL; + } + } else { + break; + } + } + + /* update nearest timer */ + update_physical_timer(cpu_timer); +} + +void initialize_timer(struct hv_timer *timer, + timer_handle_t func, void *priv_data, + uint64_t timeout, uint64_t period_in_cycle) +{ + if (timer != NULL) { + timer->func = func; + timer->priv_data = priv_data; + timer->timeout = timeout; + if (period_in_cycle > 0UL) { + timer->mode = TICK_MODE_PERIODIC; + timer->period_in_cycle = period_in_cycle; + } else { + timer->mode = TICK_MODE_ONESHOT; + timer->period_in_cycle = 0UL; + } + INIT_LIST_HEAD(&timer->node); + } +} + +void update_timer(struct hv_timer *timer, uint64_t timeout, uint64_t period_in_cycle) +{ + if (timer != NULL) { + timer->timeout = timeout; + if (period_in_cycle > 0UL) { + timer->mode = TICK_MODE_PERIODIC; + timer->period_in_cycle = period_in_cycle; + } else { + timer->mode = TICK_MODE_ONESHOT; + timer->period_in_cycle = 0UL; + } + } +} + +void timer_init(void) +{ + uint16_t pcpu_id = get_pcpu_id(); + + init_percpu_timer(pcpu_id); + + if (pcpu_id == BSP_CPU_ID) { + register_softirq(SOFTIRQ_TIMER, timer_softirq); + } + + init_hw_timer(); +} diff --git a/hypervisor/common/trusty_hypercall.c b/hypervisor/common/trusty_hypercall.c index 187fe08024..e2f70e33db 100644 --- a/hypervisor/common/trusty_hypercall.c +++ b/hypervisor/common/trusty_hypercall.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include #include #include #include diff --git a/hypervisor/common/udelay.c b/hypervisor/common/udelay.c new file mode 100644 index 0000000000..8c6e5ba3ea --- /dev/null +++ b/hypervisor/common/udelay.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +void udelay(uint32_t us) +{ + uint64_t dest_cycles, delta_cycles; + + /* Calculate number of ticks to wait */ + delta_cycles = us_to_cycles(us); + dest_cycles = get_cpu_cycles() + delta_cycles; + + /* Loop until time expired */ + while (get_cpu_cycles() < dest_cycles) { + } +} diff --git a/hypervisor/common/vm_load.c b/hypervisor/common/vm_load.c index 145d6d7204..d598ddd842 100644 --- a/hypervisor/common/vm_load.c +++ b/hypervisor/common/vm_load.c @@ -4,11 +4,11 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/hypervisor/arch/x86/seed/seed.c b/hypervisor/crypto/seed.c similarity index 51% rename from hypervisor/arch/x86/seed/seed.c rename to hypervisor/crypto/seed.c index 68f4f8a088..d438075395 100644 --- a/hypervisor/arch/x86/seed/seed.c +++ b/hypervisor/crypto/seed.c @@ -4,18 +4,16 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include -#include -#include +#include +#include #include -#include +#include #include -#include +#include #include #include #include -#include -#include "seed_abl.h" -#include "seed_sbl.h" +#include #define BOOTLOADER_SBL 0U #define BOOTLOADER_ABL 1U @@ -27,6 +25,13 @@ struct seed_argument { uint64_t addr; }; +/* Structure of physical seed */ +struct physical_seed { + struct seed_info seed_list[BOOTLOADER_SEED_MAX_ENTRIES]; + uint32_t num_seeds; + uint32_t pad; +}; + #define SEED_ARG_NUM 4U static struct seed_argument seed_arg[SEED_ARG_NUM] = { { "ImageBootParamsAddr=", BOOTLOADER_SBL, 0UL }, @@ -37,6 +42,200 @@ static struct seed_argument seed_arg[SEED_ARG_NUM] = { static struct physical_seed g_phy_seed; +#define SEED_ENTRY_TYPE_SVNSEED 0x1U +/* #define SEED_ENTRY_TYPE_RPMBSEED 0x2U */ + +/* #define SEED_ENTRY_USAGE_USEED 0x1U */ +#define SEED_ENTRY_USAGE_DSEED 0x2U + +struct seed_list_hob { + uint8_t revision; + uint8_t reserved0[3]; + uint32_t buffer_size; + uint8_t total_seed_count; + uint8_t reserved1[3]; +}; + +struct seed_entry { + /* SVN based seed or RPMB seed or attestation key_box */ + uint8_t type; + /* For SVN seed: useed or dseed + * For RPMB seed: serial number based or not + */ + uint8_t usage; + /* index for the same type and usage seed */ + uint8_t index; + uint8_t reserved; + /* reserved for future use */ + uint16_t flags; + /* Total size of this seed entry */ + uint16_t seed_entry_size; + /* SVN seed: struct seed_info + * RPMB seed: uint8_t rpmb_key[key_len] + */ + uint8_t seed[0]; +}; + +struct image_boot_params { + uint32_t size_of_this_struct; + uint32_t version; + uint64_t p_seed_list; + uint64_t p_platform_info; + uint64_t reserved; +}; + +#define ABL_SEED_LEN 32U +struct abl_seed_info { + uint8_t svn; + uint8_t reserved[3]; + uint8_t seed[ABL_SEED_LEN]; +}; + +#define ABL_SEED_LIST_MAX 4U +struct abl_svn_seed { + uint32_t size_of_this_struct; + uint32_t version; + uint32_t num_seeds; + struct abl_seed_info seed_list[ABL_SEED_LIST_MAX]; +}; + +/* + * parse_seed_abl + * + * description: + * This function parse seed_list which provided by ABL. + * + * input: + * cmdline pointer to cmdline string + * + * output: + * phy_seed pointer to physical seed structure + * + * return value: + * true if parse successfully, otherwise false. + */ +static bool parse_seed_abl(uint64_t addr, struct physical_seed *phy_seed) +{ + uint32_t i; + uint32_t legacy_seed_index = 0U; + struct seed_info *seed_list; + struct abl_svn_seed *abl_seed = (struct abl_svn_seed *)hpa2hva(addr); + bool status = false; + + if ((phy_seed != NULL) && (abl_seed != NULL) && + (abl_seed->num_seeds >= 2U) && (abl_seed->num_seeds <= ABL_SEED_LIST_MAX)) { + + seed_list = phy_seed->seed_list; + /* + * The seed_list from ABL contains several seeds which based on SVN + * and one legacy seed which is not based on SVN. The legacy seed's + * svn value is minimum in the seed list. And CSE ensures at least two + * seeds will be generated which will contain the legacy seed. + * Here find the legacy seed index first. + */ + for (i = 1U; i < abl_seed->num_seeds; i++) { + if (abl_seed->seed_list[i].svn < abl_seed->seed_list[legacy_seed_index].svn) { + legacy_seed_index = i; + } + } + + /* + * Copy out abl_seed for trusty and clear the original seed in memory. + * The SOS requires the legacy seed to derive RPMB key. So skip the + * legacy seed when clear original seed. + */ + (void)memset((void *)&phy_seed->seed_list[0U], 0U, sizeof(phy_seed->seed_list)); + for (i = 0U; i < abl_seed->num_seeds; i++) { + seed_list[i].cse_svn = abl_seed->seed_list[i].svn; + (void)memcpy_s((void *)&seed_list[i].seed[0U], sizeof(seed_list[i].seed), + (void *)&abl_seed->seed_list[i].seed[0U], sizeof(abl_seed->seed_list[i].seed)); + + if (i == legacy_seed_index) { + continue; + } + + (void)memset((void *)&abl_seed->seed_list[i].seed[0U], 0U, + sizeof(abl_seed->seed_list[i].seed)); + } + + phy_seed->num_seeds = abl_seed->num_seeds; + status = true; + } + + return status; +} + +/* + * parse_seed_sbl + * + * description: + * This function parse seed_list which provided by SBL + * + * input: + * cmdline pointer to cmdline string + * + * return value: + * true if parse successfully, otherwise false. + */ +static bool parse_seed_sbl(uint64_t addr, struct physical_seed *phy_seed) +{ + uint8_t i; + uint8_t dseed_index = 0U; + struct image_boot_params *boot_params = NULL; + struct seed_list_hob *seed_hob = NULL; + struct seed_entry *entry = NULL; + struct seed_info *seed_list = NULL; + bool status = false; + + boot_params = (struct image_boot_params *)hpa2hva(addr); + + if (boot_params != NULL) { + seed_hob = (struct seed_list_hob *)hpa2hva(boot_params->p_seed_list); + } + + if ((seed_hob != NULL) && (phy_seed != NULL)) { + status = true; + + seed_list = phy_seed->seed_list; + + entry = (struct seed_entry *)((uint8_t *)seed_hob + sizeof(struct seed_list_hob)); + + for (i = 0U; i < seed_hob->total_seed_count; i++) { + if (entry != NULL) { + /* retrieve dseed */ + if ((SEED_ENTRY_TYPE_SVNSEED == entry->type) && + (SEED_ENTRY_USAGE_DSEED == entry->usage)) { + + /* The seed_entry with same type/usage are always + * arranged by index in order of 0~3. + */ + if ((entry->index != dseed_index) || + (entry->index >= BOOTLOADER_SEED_MAX_ENTRIES)) { + status = false; + break; + } + + (void)memcpy_s((void *)&seed_list[dseed_index], sizeof(struct seed_info), + (void *)&entry->seed[0U], sizeof(struct seed_info)); + dseed_index++; + + /* erase original seed in seed entry */ + (void)memset((void *)&entry->seed[0U], 0U, sizeof(struct seed_info)); + } + + entry = (struct seed_entry *)((uint8_t *)entry + entry->seed_entry_size); + } + } + + if (status) { + phy_seed->num_seeds = dseed_index; + } + } + + return status; +} + + static uint32_t parse_seed_arg(void) { const char *cmd_src = NULL; diff --git a/hypervisor/debug/console.c b/hypervisor/debug/console.c index 686235b773..19e54b2841 100644 --- a/hypervisor/debug/console.c +++ b/hypervisor/debug/console.c @@ -12,10 +12,11 @@ #include #include #include -#include +#include #include #include #include +#include struct hv_timer console_timer; @@ -159,13 +160,13 @@ static void console_timer_callback(__unused void *data) void console_setup_timer(void) { - uint64_t period_in_cycle, fire_tsc; + uint64_t period_in_cycle, deadline; period_in_cycle = CYCLES_PER_MS * CONSOLE_KICK_TIMER_TIMEOUT; - fire_tsc = rdtsc() + period_in_cycle; + deadline = get_cpu_cycles() + period_in_cycle; initialize_timer(&console_timer, console_timer_callback, NULL, - fire_tsc, TICK_MODE_PERIODIC, period_in_cycle); + deadline, period_in_cycle); /* Start an periodic timer */ if (add_timer(&console_timer) != 0) { diff --git a/hypervisor/debug/dump.c b/hypervisor/debug/dump.c index de4f9bd373..03e28260e6 100644 --- a/hypervisor/debug/dump.c +++ b/hypervisor/debug/dump.c @@ -5,12 +5,12 @@ */ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/hypervisor/debug/hypercall.c b/hypervisor/debug/hypercall.c index 9a5271a151..d41ce26792 100644 --- a/hypervisor/debug/hypercall.c +++ b/hypervisor/debug/hypercall.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #ifdef PROFILING_ON diff --git a/hypervisor/debug/logmsg.c b/hypervisor/debug/logmsg.c index 31d2d41f9f..a6a5cfece6 100644 --- a/hypervisor/debug/logmsg.c +++ b/hypervisor/debug/logmsg.c @@ -5,12 +5,13 @@ */ #include -#include +#include #include -#include -#include +#include +#include #include #include +#include /* buf size should be identical to the size in hvlog option, which is * transfered to SOS: @@ -53,10 +54,10 @@ void do_logmsg(uint32_t severity, const char *fmt, ...) } /* Get time-stamp value */ - timestamp = rdtsc(); + timestamp = get_cpu_cycles(); /* Scale time-stamp appropriately */ - timestamp = ticks_to_us(timestamp); + timestamp = cycles_to_us(timestamp); /* Get CPU ID */ pcpu_id = get_pcpu_id(); diff --git a/hypervisor/debug/npk_log.c b/hypervisor/debug/npk_log.c index eb9e16628b..c953a0f8e3 100644 --- a/hypervisor/debug/npk_log.c +++ b/hypervisor/debug/npk_log.c @@ -4,11 +4,11 @@ */ #include -#include +#include #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/hypervisor/debug/profiling.c b/hypervisor/debug/profiling.c index ef71e86518..2823c19500 100644 --- a/hypervisor/debug/profiling.c +++ b/hypervisor/debug/profiling.c @@ -7,12 +7,16 @@ #include #include +#include +#include +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include @@ -339,7 +343,7 @@ static int32_t profiling_generate_data(int32_t collector, uint32_t type) clac(); /* populate the data header */ - pkt_header.tsc = rdtsc(); + pkt_header.tsc = get_cpu_cycles(); pkt_header.collector_id = collector; pkt_header.cpu_id = get_pcpu_id(); pkt_header.data_type = 1U << type; @@ -411,7 +415,7 @@ static int32_t profiling_generate_data(int32_t collector, uint32_t type) clac(); /* populate the data header */ - pkt_header.tsc = rdtsc(); + pkt_header.tsc = get_cpu_cycles(); pkt_header.collector_id = collector; pkt_header.cpu_id = get_pcpu_id(); pkt_header.data_type = (uint16_t)type; @@ -637,16 +641,16 @@ static void profiling_pmi_handler(uint32_t irq, __unused void *data) get_cpu_var(profiling_info.vm_info).external_vector = -1; /* Attribute PMI to hypervisor context */ } else { + struct x86_irq_data *irqd = irq_desc_array[irq].arch_data; psample->csample.os_id = 0xFFFFU; (void)memcpy_s(psample->csample.task, 16, "VMM\0", 4); psample->csample.cpu_id = get_pcpu_id(); psample->csample.process_id = 0U; psample->csample.task_id = 0U; psample->csample.overflow_status = perf_ovf_status; - psample->csample.rip = irq_desc_array[irq].ctx_rip; - psample->csample.rflags - = (uint32_t)irq_desc_array[irq].ctx_rflags; - psample->csample.cs = (uint32_t)irq_desc_array[irq].ctx_cs; + psample->csample.rip = irqd->ctx_rip; + psample->csample.rflags = (uint32_t)irqd->ctx_rflags; + psample->csample.cs = (uint32_t)irqd->ctx_cs; } if ((sep_collection_switch & @@ -1308,7 +1312,7 @@ void profiling_vmenter_handler(__unused struct acrn_vcpu *vcpu) ((socwatch_collection_switch & (1UL << (uint64_t)SOCWATCH_VM_SWITCH_TRACING)) > 0UL))) { - get_cpu_var(profiling_info.vm_info).vmenter_tsc = rdtsc(); + get_cpu_var(profiling_info.vm_info).vmenter_tsc = get_cpu_cycles(); } } @@ -1324,7 +1328,7 @@ void profiling_pre_vmexit_handler(struct acrn_vcpu *vcpu) if ((get_cpu_var(profiling_info.s_state).pmu_state == PMU_RUNNING) || (get_cpu_var(profiling_info.soc_state) == SW_RUNNING)) { - get_cpu_var(profiling_info.vm_info).vmexit_tsc = rdtsc(); + get_cpu_var(profiling_info.vm_info).vmexit_tsc = get_cpu_cycles(); get_cpu_var(profiling_info.vm_info).vmexit_reason = exit_reason; if (exit_reason == VMX_EXIT_REASON_EXTERNAL_INTERRUPT) { diff --git a/hypervisor/debug/sbuf.c b/hypervisor/debug/sbuf.c index 516830d6a4..59a0a498d0 100644 --- a/hypervisor/debug/sbuf.c +++ b/hypervisor/debug/sbuf.c @@ -12,8 +12,8 @@ #include #include #include -#include -#include +#include +#include uint32_t sbuf_next_ptr(uint32_t pos_arg, uint32_t span, uint32_t scope) diff --git a/hypervisor/debug/shell.c b/hypervisor/debug/shell.c index 63fd4015fa..265563630c 100644 --- a/hypervisor/debug/shell.c +++ b/hypervisor/debug/shell.c @@ -6,22 +6,23 @@ #include #include -#include +#include #include "shell_priv.h" +#include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include +#include +#include #define TEMP_STR_SIZE 60U #define MAX_STR_SIZE 256U @@ -1047,63 +1048,44 @@ static int32_t shell_show_cpu_int(__unused int32_t argc, __unused char **argv) return 0; } -static void get_entry_info(const struct ptirq_remapping_info *entry, char *type, +static void get_entry_info(const struct ptintr *intr, char *type, uint32_t *irq, uint32_t *vector, uint64_t *dest, bool *lvl_tm, uint32_t *pgsi, uint32_t *vgsi, uint32_t *bdf, uint32_t *vbdf) { - if (is_entry_active(entry)) { - if (entry->intr_type == PTDEV_INTR_MSI) { - (void)strncpy_s(type, 16U, "MSI", 16U); - *dest = entry->pmsi.addr.bits.dest_field; - if (entry->pmsi.data.bits.trigger_mode == MSI_DATA_TRGRMODE_LEVEL) { - *lvl_tm = true; - } else { - *lvl_tm = false; - } - *pgsi = INVALID_INTERRUPT_PIN; - *vgsi = INVALID_INTERRUPT_PIN; - *bdf = entry->phys_sid.msi_id.bdf; - *vbdf = entry->virt_sid.msi_id.bdf; - } else { - uint32_t phys_irq = entry->allocated_pirq; - union ioapic_rte rte; + uint32_t phys_irq = ptirq_get_irq(intr->irq); + + if (intr->intr_type == PTDEV_INTR_MSI) { + (void)strncpy_s(type, 16U, "MSI", 16U); + *dest = intr->pmsi.addr.bits.dest_field; + *lvl_tm = (intr->pmsi.data.bits.trigger_mode == MSI_DATA_TRGRMODE_LEVEL); + *pgsi = INVALID_INTERRUPT_PIN; + *vgsi = INVALID_INTERRUPT_PIN; + *bdf = intr->phys_sid.msi_id.bdf; + *vbdf = intr->virt_sid.msi_id.bdf; + } else { + union ioapic_rte rte; - if (entry->virt_sid.intx_id.ctlr == INTX_CTLR_IOAPIC) { - (void)strncpy_s(type, 16U, "IOAPIC", 16U); - } else { - (void)strncpy_s(type, 16U, "PIC", 16U); - } - ioapic_get_rte(phys_irq, &rte); - *dest = rte.bits.dest_field; - if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) { - *lvl_tm = true; - } else { - *lvl_tm = false; - } - *pgsi = entry->phys_sid.intx_id.gsi; - *vgsi = entry->virt_sid.intx_id.gsi; - *bdf = 0U; - *vbdf = 0U; + if (intr->virt_sid.intx_id.ctlr == INTX_CTLR_IOAPIC) { + (void)strncpy_s(type, 16U, "IOAPIC", 16U); + } else { + (void)strncpy_s(type, 16U, "PIC", 16U); } - *irq = entry->allocated_pirq; - *vector = irq_to_vector(entry->allocated_pirq); - } else { - (void)strncpy_s(type, 16U, "NONE", 16U); - *irq = IRQ_INVALID; - *vector = 0U; - *dest = 0UL; - *lvl_tm = 0; - *pgsi = ~0U; - *vgsi = ~0U; + ioapic_get_rte(phys_irq, &rte); + *dest = rte.bits.dest_field; + *lvl_tm = (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL); + *pgsi = intr->phys_sid.intx_id.gsi; + *vgsi = intr->virt_sid.intx_id.gsi; *bdf = 0U; *vbdf = 0U; } + *irq = phys_irq; + *vector = irq_to_vector(phys_irq); } static void get_ptdev_info(char *str_arg, size_t str_max) { char *str = str_arg; - struct ptirq_remapping_info *entry; + struct ptintr *intr; uint16_t idx; size_t len, size = str_max; uint32_t irq, vector; @@ -1120,13 +1102,14 @@ static void get_ptdev_info(char *str_arg, size_t str_max) size -= len; str += len; - for (idx = 0U; idx < CONFIG_MAX_PT_IRQ_ENTRIES; idx++) { - entry = &ptirq_entries[idx]; - if (is_entry_active(entry)) { - get_entry_info(entry, type, &irq, &vector, &dest, &lvl_tm, &pgsi, &vgsi, + for (idx = 0U; idx < ARRAY_SIZE(ptintr_entries); idx++) { + /* lockless retrieval */ + intr = &ptintr_entries[idx]; + if (intr->active) { + get_entry_info(intr, type, &irq, &vector, &dest, &lvl_tm, &pgsi, &vgsi, (uint32_t *)&bdf, (uint32_t *)&vbdf); len = snprintf(str, size, "\r\n%d\t%s\t%d\t0x%X\t0x%X", - entry->vm->vm_id, type, irq, vector, dest); + intr->vm->vm_id, type, irq, vector, dest); if (len >= size) { goto overflow; } @@ -1134,7 +1117,7 @@ static void get_ptdev_info(char *str_arg, size_t str_max) str += len; len = snprintf(str, size, "\t%s\t%hhu\t%hhu\t%x:%x.%x\t%x:%x.%x", - is_entry_active(entry) ? (lvl_tm ? "level" : "edge") : "none", + lvl_tm ? "level" : "edge", pgsi, vgsi, bdf.bits.b, bdf.bits.d, bdf.bits.f, vbdf.bits.b, vbdf.bits.d, vbdf.bits.f); if (len >= size) { diff --git a/hypervisor/debug/shell_priv.h b/hypervisor/debug/shell_priv.h index af741aa264..6e07078d1c 100644 --- a/hypervisor/debug/shell_priv.h +++ b/hypervisor/debug/shell_priv.h @@ -7,7 +7,7 @@ #ifndef SHELL_PRIV_H #define SHELL_PRIV_H -#include +#include #define SHELL_CMD_MAX_LEN 100U #define SHELL_STRING_MAX_LEN (PAGE_SIZE << 2U) diff --git a/hypervisor/debug/trace.c b/hypervisor/debug/trace.c index 0ff7d9fdc1..97f218ccb8 100644 --- a/hypervisor/debug/trace.c +++ b/hypervisor/debug/trace.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #define TRACE_CUSTOM 0xFCU @@ -51,7 +51,7 @@ static inline void trace_put(uint16_t cpu_id, uint32_t evid, uint32_t n_data, st { struct shared_buf *sbuf = per_cpu(sbuf, cpu_id)[ACRN_TRACE]; - entry->tsc = rdtsc(); + entry->tsc = get_cpu_cycles(); entry->id = evid; entry->n_data = (uint8_t)n_data; entry->cpu = (uint8_t)cpu_id; diff --git a/hypervisor/debug/uart16550.c b/hypervisor/debug/uart16550.c index 8d460109de..b6d845ac91 100644 --- a/hypervisor/debug/uart16550.c +++ b/hypervisor/debug/uart16550.c @@ -5,12 +5,12 @@ */ #include -#include +#include #include -#include +#include #include -#include -#include +#include +#include #define MAX_BDF_LEN 8 diff --git a/hypervisor/dm/io_req.c b/hypervisor/dm/io_req.c index f9f69e56c6..b5469ba53f 100644 --- a/hypervisor/dm/io_req.c +++ b/hypervisor/dm/io_req.c @@ -3,14 +3,20 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include +#include +#include +#include #include #include #include #define DBG_LEVEL_IOREQ 6U +#define HYPERVISOR_CALLBACK_VHM_VECTOR 0xF3U + static uint32_t acrn_vhm_notification_vector = HYPERVISOR_CALLBACK_VHM_VECTOR; + #define MMIO_DEFAULT_VALUE_SIZE_1 (0xFFUL) #define MMIO_DEFAULT_VALUE_SIZE_2 (0xFFFFUL) #define MMIO_DEFAULT_VALUE_SIZE_4 (0xFFFFFFFFUL) diff --git a/hypervisor/dm/mmio_dev.c b/hypervisor/dm/mmio_dev.c index 7fd69306b3..8ecb2dc21f 100644 --- a/hypervisor/dm/mmio_dev.c +++ b/hypervisor/dm/mmio_dev.c @@ -7,9 +7,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include int32_t assign_mmio_dev(struct acrn_vm *vm, const struct acrn_mmiodev *mmiodev) { diff --git a/hypervisor/dm/vgpio.c b/hypervisor/dm/vgpio.c index 8e18a3ade8..23fa9db4cb 100644 --- a/hypervisor/dm/vgpio.c +++ b/hypervisor/dm/vgpio.c @@ -38,11 +38,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #ifdef P2SB_VGPIO_DM_ENABLED diff --git a/hypervisor/dm/vioapic.c b/hypervisor/dm/vioapic.c index 5e02497e3c..6327b4abc6 100644 --- a/hypervisor/dm/vioapic.c +++ b/hypervisor/dm/vioapic.c @@ -30,13 +30,18 @@ #define pr_prefix "vioapic: " -#include #include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define RTBL_RO_BITS ((uint32_t)0x00004000U | (uint32_t)0x00001000U) /*Remote IRR and Delivery Status bits*/ @@ -302,8 +307,10 @@ static void vioapic_indirect_write(struct acrn_single_vioapic *vioapic, uint32_t bool wire_mode_valid = true; uint32_t addr_offset = regnum - IOAPIC_REDTBL; uint32_t rte_offset = addr_offset >> 1U; - pin = rte_offset; + struct ptintr_add_args intx_add; + struct ptintr_remap_args intx_remap; + pin = rte_offset; last = vioapic->rtbl[pin]; new = last; if ((addr_offset & 1U) != 0U) { @@ -354,8 +361,16 @@ static void vioapic_indirect_write(struct acrn_single_vioapic *vioapic, uint32_t if ((new.bits.intr_mask == IOAPIC_RTE_MASK_CLR) || (last.bits.intr_mask == IOAPIC_RTE_MASK_CLR)) { /* VM enable intr */ /* NOTE: only support max 256 pin */ - - (void)ptirq_intx_pin_remap(vioapic->vm, vioapic->chipinfo.gsi_base + pin, INTX_CTLR_IOAPIC); + intx_add.intr_type = PTDEV_INTR_INTX; + intx_add.intx.virt_gsi = vioapic->chipinfo.gsi_base + pin; + intx_add.intx.virt_ctlr = INTX_CTLR_IOAPIC; + intx_add.intx.phys_gsi = intx_add.intx.virt_gsi; + intx_add.intx.phys_ctlr = INTX_CTLR_IOAPIC; + (void)ptintr_add(vioapic->vm, &intx_add); + intx_remap.intr_type = PTDEV_INTR_INTX; + intx_remap.intx.virt_gsi = vioapic->chipinfo.gsi_base + pin; + intx_remap.intx.virt_ctlr = INTX_CTLR_IOAPIC; + (void)ptintr_remap(vioapic->vm, &intx_remap); } /* @@ -430,6 +445,7 @@ vioapic_process_eoi(struct acrn_single_vioapic *vioapic, uint32_t vector) } dev_dbg(DBG_LEVEL_VIOAPIC, "ioapic processing eoi for vector %u", vector); + spinlock_irqsave_obtain(&(vioapic->lock), &rflags); /* notify device to ack if assigned pin */ for (pin = 0U; pin < pincount; pin++) { @@ -439,14 +455,13 @@ vioapic_process_eoi(struct acrn_single_vioapic *vioapic, uint32_t vector) continue; } - ptirq_intx_ack(vioapic->vm, vioapic->chipinfo.gsi_base + pin, INTX_CTLR_IOAPIC); + ptintr_intx_ack(vioapic->vm, vioapic->chipinfo.gsi_base + pin, INTX_CTLR_IOAPIC); } /* * XXX keep track of the pins associated with this vector instead * of iterating on every single pin each time. */ - spinlock_irqsave_obtain(&(vioapic->lock), &rflags); for (pin = 0U; pin < pincount; pin++) { rte = vioapic->rtbl[pin]; if ((rte.bits.vector != vector) || diff --git a/hypervisor/dm/vpci/ivshmem.c b/hypervisor/dm/vpci/ivshmem.c index 304908a586..f73db2915d 100644 --- a/hypervisor/dm/vpci/ivshmem.c +++ b/hypervisor/dm/vpci/ivshmem.c @@ -5,9 +5,9 @@ */ #ifdef CONFIG_IVSHMEM_ENABLED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index 18a36578ba..e80e0c1b9f 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -26,14 +26,13 @@ * * $FreeBSD$ */ -#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include "vpci_priv.h" @@ -81,6 +80,38 @@ static void mask_one_msix_vector(const struct pci_vdev *vdev, uint32_t index) clac(); } +struct vmsix_remap_args { + const struct pci_vdev *vdev; + struct msi_info *info; + uint32_t index; +}; + +static int32_t remap_vmsix_cb(void *a) +{ + struct vmsix_remap_args *args = a; + const struct pci_vdev *vdev = args->vdev; + struct msi_info *pmsi = args->info; + struct msix_table_entry *pentry; + uint32_t index = args->index; + + /* Write the table entry to the physical structure */ + pentry = get_msix_table_entry(vdev, index); + + /* + * PCI 3.0 Spec allows writing to Message Address and Message Upper Address + * fields with a single QWORD write, but some hardware can accept 32 bits + * write only + */ + stac(); + mmio_write32((uint32_t)(pmsi->addr.full), (void *)&(pentry->addr)); + mmio_write32((uint32_t)(pmsi->addr.full >> 32U), (void *)((char *)&(pentry->addr) + 4U)); + + mmio_write32(pmsi->data.full, (void *)&(pentry->data)); + mmio_write32(vdev->msix.table_entries[index].vector_control, (void *)&(pentry->vector_control)); + clac(); + + return 0; +} /** * @pre vdev != NULL @@ -89,10 +120,13 @@ static void mask_one_msix_vector(const struct pci_vdev *vdev, uint32_t index) */ static void remap_one_vmsix_entry(const struct pci_vdev *vdev, uint32_t index) { + struct acrn_vm *vm = vpci2vm(vdev->vpci); const struct msix_table_entry *ventry; - struct msix_table_entry *pentry; struct msi_info info = {}; - int32_t ret; + struct ptintr_add_args msix_add; + struct ptintr_remap_args msix_remap; + struct vmsix_remap_args remap_arg = + { .vdev = vdev, .info = &info, .index = index }; mask_one_msix_vector(vdev, index); ventry = &vdev->msix.table_entries[index]; @@ -100,24 +134,21 @@ static void remap_one_vmsix_entry(const struct pci_vdev *vdev, uint32_t index) info.addr.full = vdev->msix.table_entries[index].addr; info.data.full = vdev->msix.table_entries[index].data; - ret = ptirq_prepare_msix_remap(vpci2vm(vdev->vpci), vdev->bdf.value, vdev->pdev->bdf.value, - (uint16_t)index, &info, INVALID_IRTE_ID); - if (ret == 0) { - /* Write the table entry to the physical structure */ - pentry = get_msix_table_entry(vdev, index); - - /* - * PCI 3.0 Spec allows writing to Message Address and Message Upper Address - * fields with a single QWORD write, but some hardware can accept 32 bits - * write only - */ - stac(); - mmio_write32((uint32_t)(info.addr.full), (void *)&(pentry->addr)); - mmio_write32((uint32_t)(info.addr.full >> 32U), (void *)((char *)&(pentry->addr) + 4U)); - - mmio_write32(info.data.full, (void *)&(pentry->data)); - mmio_write32(vdev->msix.table_entries[index].vector_control, (void *)&(pentry->vector_control)); - clac(); + msix_add.intr_type = PTDEV_INTR_MSI; + msix_add.msix.virt_bdf = vdev->bdf.value; + msix_add.msix.phys_bdf = vdev->pdev->bdf.value; + msix_add.msix.entry_nr = (uint16_t)index; + + /* the goal is to only add once */ + if (ptintr_add(vm, &msix_add) == 0) { + msix_remap.intr_type = PTDEV_INTR_MSI; + msix_remap.msix.virt_bdf = vdev->bdf.value; + msix_remap.msix.entry_nr = (uint16_t)index; + msix_remap.msix.irte_idx = INVALID_IRTE_ID; + msix_remap.msix.info = &info; + msix_remap.msix.remap_arg = (void *)&remap_arg; + msix_remap.msix.remap_cb = remap_vmsix_cb; + (void)ptintr_remap(vm, &msix_remap); } } @@ -463,10 +494,19 @@ void init_vmsix_pt(struct pci_vdev *vdev) */ void deinit_vmsix_pt(struct pci_vdev *vdev) { + uint32_t i; + struct ptintr_rmv_args msix_rmv; + if (has_msix_cap(vdev)) { if (vdev->msix.table_count != 0U) { - ptirq_remove_msix_remapping(vpci2vm(vdev->vpci), vdev->pdev->bdf.value, vdev->msix.table_count); - (void)memset((void *)&vdev->msix.table_entries, 0U, sizeof(vdev->msix.table_entries)); + msix_rmv.intr_type = PTDEV_INTR_MSI; + msix_rmv.msix.phys_bdf = vdev->pdev->bdf.value; + + for (i = 0U; i < vdev->msix.table_count; i++) { + msix_rmv.msix.entry_nr = i; + ptintr_remove_and_unmap(vpci2vm(vdev->vpci), &msix_rmv); + } + (void)memset((void *)&vdev->msix, 0U, sizeof(vdev->msix)); vdev->msix.is_vmsix_on_msi_programmed = false; } } diff --git a/hypervisor/dm/vpci/vdev.c b/hypervisor/dm/vpci/vdev.c index 99927e381d..057129dfbb 100644 --- a/hypervisor/dm/vpci/vdev.c +++ b/hypervisor/dm/vpci/vdev.c @@ -27,9 +27,9 @@ * $FreeBSD$ */ -#include +#include #include "vpci_priv.h" -#include +#include #include #include diff --git a/hypervisor/dm/vpci/vhostbridge.c b/hypervisor/dm/vpci/vhostbridge.c index eed841e537..b9d0cf8437 100644 --- a/hypervisor/dm/vpci/vhostbridge.c +++ b/hypervisor/dm/vpci/vhostbridge.c @@ -34,7 +34,7 @@ * Series Host Bridge (rev 0b) */ -#include +#include #include #include "vpci_priv.h" #include diff --git a/hypervisor/dm/vpci/vmcs9900.c b/hypervisor/dm/vpci/vmcs9900.c index 2fea12c613..d616419210 100644 --- a/hypervisor/dm/vpci/vmcs9900.c +++ b/hypervisor/dm/vpci/vmcs9900.c @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include +#include +#include #include #include #include diff --git a/hypervisor/dm/vpci/vmsi.c b/hypervisor/dm/vpci/vmsi.c index 0f9c0c9740..755f034fa1 100644 --- a/hypervisor/dm/vpci/vmsi.c +++ b/hypervisor/dm/vpci/vmsi.c @@ -27,11 +27,10 @@ * $FreeBSD$ */ -#include -#include -#include +#include +#include #include -#include +#include #include "vpci_priv.h" @@ -52,6 +51,37 @@ static inline void enable_disable_msi(const struct pci_vdev *vdev, bool enable) } pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_CTRL, 2U, msgctrl); } + +struct vmsi_remap_args { + const struct pci_vdev *vdev; + struct msi_info *info; +}; + +static int32_t remap_vmsi_cb(void *a) +{ + struct vmsi_remap_args *args = a; + const struct pci_vdev *vdev = args->vdev; + struct msi_info *pmsi = args->info; + union pci_bdf pbdf = vdev->pdev->bdf; + uint32_t capoff = vdev->msi.capoff; + + pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR, 0x4U, (uint32_t)pmsi->addr.full); + + if (vdev->msi.is_64bit) { + pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U, + (uint32_t)(pmsi->addr.full >> 32U)); + pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA_64BIT, 0x2U, + (uint16_t)pmsi->data.full); + } else { + pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA, 0x2U, (uint16_t)pmsi->data.full); + } + + /* If MSI Enable is being set, make sure INTxDIS bit is set */ + enable_disable_pci_intx(pbdf, false); + enable_disable_msi(vdev, true); + return 0; +} + /** * @brief Remap vMSI virtual address and data to MSI physical address and data * This function is called when physical MSI is disabled. @@ -65,6 +95,9 @@ static void remap_vmsi(const struct pci_vdev *vdev) struct msi_info info = {}; union pci_bdf pbdf = vdev->pdev->bdf; struct acrn_vm *vm = vpci2vm(vdev->vpci); + struct ptintr_add_args msix_add; + struct ptintr_remap_args msix_remap; + struct vmsi_remap_args remap_arg = { .vdev = vdev, .info = &info }; uint32_t capoff = vdev->msi.capoff; uint32_t vmsi_msgdata, vmsi_addrlo, vmsi_addrhi = 0U; @@ -79,19 +112,21 @@ static void remap_vmsi(const struct pci_vdev *vdev) info.addr.full = (uint64_t)vmsi_addrlo | ((uint64_t)vmsi_addrhi << 32U); info.data.full = vmsi_msgdata; - if (ptirq_prepare_msix_remap(vm, vdev->bdf.value, pbdf.value, 0U, &info, INVALID_IRTE_ID) == 0) { - pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR, 0x4U, (uint32_t)info.addr.full); - if (vdev->msi.is_64bit) { - pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U, - (uint32_t)(info.addr.full >> 32U)); - pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA_64BIT, 0x2U, (uint16_t)info.data.full); - } else { - pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA, 0x2U, (uint16_t)info.data.full); - } - - /* If MSI Enable is being set, make sure INTxDIS bit is set */ - enable_disable_pci_intx(pbdf, false); - enable_disable_msi(vdev, true); + msix_add.intr_type = PTDEV_INTR_MSI; + msix_add.msix.virt_bdf = vdev->bdf.value; + msix_add.msix.phys_bdf = pbdf.value; + msix_add.msix.entry_nr = 0U; + + /* the goal is to only add once */ + if (ptintr_add(vm, &msix_add) == 0) { + msix_remap.intr_type = PTDEV_INTR_MSI; + msix_remap.msix.virt_bdf = vdev->bdf.value; + msix_remap.msix.entry_nr = 0U; + msix_remap.msix.irte_idx = INVALID_IRTE_ID; + msix_remap.msix.info = &info; + msix_remap.msix.remap_arg = (void *)&remap_arg; + msix_remap.msix.remap_cb = remap_vmsi_cb; + (void)ptintr_remap(vm, &msix_remap); } } @@ -127,8 +162,14 @@ void write_vmsi_cap_reg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, */ void deinit_vmsi(const struct pci_vdev *vdev) { + struct ptintr_rmv_args msi_rmv; + if (has_msi_cap(vdev)) { - ptirq_remove_msix_remapping(vpci2vm(vdev->vpci), vdev->pdev->bdf.value, 1U); + msi_rmv.intr_type = PTDEV_INTR_MSI; + msi_rmv.msix.phys_bdf = vdev->pdev->bdf.value; + msi_rmv.msix.entry_nr = 0U; + ptintr_remove_and_unmap(vpci2vm(vdev->vpci), &msi_rmv); + (void)memset((void *)&vdev->msi, 0U, sizeof(vdev->msi)); } } diff --git a/hypervisor/dm/vpci/vmsix.c b/hypervisor/dm/vpci/vmsix.c index 482121c9d1..507e454234 100644 --- a/hypervisor/dm/vpci/vmsix.c +++ b/hypervisor/dm/vpci/vmsix.c @@ -27,11 +27,11 @@ * $FreeBSD$ */ -#include +#include #include #include -#include -#include +#include +#include #include #include "vpci_priv.h" diff --git a/hypervisor/dm/vpci/vmsix_on_msi.c b/hypervisor/dm/vpci/vmsix_on_msi.c index fcd50e3482..b250533305 100644 --- a/hypervisor/dm/vpci/vmsix_on_msi.c +++ b/hypervisor/dm/vpci/vmsix_on_msi.c @@ -4,12 +4,11 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include +#include #include -#include -#include +#include +#include +#include #include "vpci_priv.h" #define PER_VECTOR_MASK_CAP 0x0100U @@ -156,16 +155,63 @@ void write_vmsix_cap_reg_on_msi(struct pci_vdev *vdev, uint32_t offset, uint32_t } } +struct vmsix_remap_args { + struct pci_vdev *vdev; + struct msi_info *info; + uint32_t index; +}; + +union irte_index { + uint16_t index; + struct { + uint16_t index_low:15; + uint16_t index_high:1; + } bits __packed; +}; + +static int32_t remap_vmsix_on_msi_cb(void *a) +{ + struct vmsix_remap_args *args = a; + struct pci_vdev *vdev = args->vdev; + struct msi_info *pmsi = args->info; + union pci_bdf pbdf = vdev->pdev->bdf; + uint32_t capoff = vdev->msix.capoff; + union irte_index ir_index; + + if (!vdev->msix.is_vmsix_on_msi_programmed) { + ir_index.index = vdev->pdev->irte_start; + pmsi->addr.ir_bits.shv = 1U; + pmsi->addr.ir_bits.intr_index_high = ir_index.bits.index_high; + pmsi->addr.ir_bits.intr_index_low = ir_index.bits.index_low; + pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR, 0x4U, (uint32_t)pmsi->addr.full); + if (vdev->msi.is_64bit) { + pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U, + (uint32_t)(pmsi->addr.full >> 32U)); + pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA_64BIT, 0x2U, + (uint16_t)pmsi->data.full); + } else { + pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA, 0x2U, + (uint16_t)pmsi->data.full); + } + vdev->msix.is_vmsix_on_msi_programmed = true; + } + + return 0; +} + void remap_one_vmsix_entry_on_msi(struct pci_vdev *vdev, uint32_t index) { const struct msix_table_entry *ventry; + struct acrn_vm *vm = vpci2vm(vdev->vpci); uint32_t mask_bits; uint32_t vector_mask = 1U << index; struct msi_info info = {}; union pci_bdf pbdf = vdev->pdev->bdf; - union irte_index ir_index; int32_t ret = 0; - uint32_t capoff = vdev->msix.capoff; + struct ptintr_add_args msix_add; + struct ptintr_remap_args msix_remap; + struct vmsix_remap_args remap_arg = + { .vdev = vdev, .info = &info, .index = index }; mask_bits = pci_pdev_read_cfg(pbdf, get_mask_bits_offset(vdev), 4U); mask_bits |= vector_mask; @@ -176,27 +222,25 @@ void remap_one_vmsix_entry_on_msi(struct pci_vdev *vdev, uint32_t index) info.addr.full = vdev->msix.table_entries[index].addr; info.data.full = vdev->msix.table_entries[index].data; - ret = ptirq_prepare_msix_remap(vpci2vm(vdev->vpci), vdev->bdf.value, pbdf.value, - (uint16_t)index, &info, vdev->pdev->irte_start + (uint16_t)index); - if (ret == 0) { - if (!vdev->msix.is_vmsix_on_msi_programmed) { - ir_index.index = vdev->pdev->irte_start; - info.addr.ir_bits.shv = 1U; - info.addr.ir_bits.intr_index_high = ir_index.bits.index_high; - info.addr.ir_bits.intr_index_low = ir_index.bits.index_low; - pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR, 0x4U, (uint32_t)info.addr.full); - if (vdev->msi.is_64bit) { - pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U, - (uint32_t)(info.addr.full >> 32U)); - pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA_64BIT, 0x2U, - (uint16_t)info.data.full); - } else { - pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_DATA, 0x2U, - (uint16_t)info.data.full); - } - vdev->msix.is_vmsix_on_msi_programmed = true; + msix_add.intr_type = PTDEV_INTR_MSI; + msix_add.msix.virt_bdf = vdev->bdf.value; + msix_add.msix.phys_bdf = vdev->pdev->bdf.value; + msix_add.msix.entry_nr = (uint16_t)index; + + /* the goal is to only add once */ + if (ptintr_add(vm, &msix_add) == 0) { + msix_remap.intr_type = PTDEV_INTR_MSI; + msix_remap.msix.virt_bdf = vdev->bdf.value; + msix_remap.msix.entry_nr = (uint16_t)index; + msix_remap.msix.irte_idx = vdev->pdev->irte_start + (uint16_t)index; + msix_remap.msix.info = &info; + msix_remap.msix.remap_arg = (void *)&remap_arg; + msix_remap.msix.remap_cb = remap_vmsix_on_msi_cb; + ret = ptintr_remap(vm, &msix_remap); + + if (ret == 0) { + mask_bits &= ~vector_mask; } - mask_bits &= ~vector_mask; } } pci_pdev_write_cfg(pbdf, get_mask_bits_offset(vdev), 4U, mask_bits); diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index 4f28ba535b..bdd445792d 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -28,15 +28,15 @@ */ #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include "vpci_priv.h" -#include "pci_dev.h" #include static void vpci_init_vdevs(struct acrn_vm *vm); @@ -273,7 +273,7 @@ void deinit_vpci(struct acrn_vm *vm) } } - ptdev_release_all_entries(vm); + ptintr_remove_and_unmap_vm(vm); (void)memset(&vm->vpci, 0U, sizeof(struct acrn_vpci)); /* Free iommu */ diff --git a/hypervisor/dm/vpci/vpci_bridge.c b/hypervisor/dm/vpci/vpci_bridge.c index 2781878615..c425f79e24 100644 --- a/hypervisor/dm/vpci/vpci_bridge.c +++ b/hypervisor/dm/vpci/vpci_bridge.c @@ -45,7 +45,7 @@ * 1. SOS how to reset PCI devices under the PCI bridge */ -#include +#include #include #include #include diff --git a/hypervisor/dm/vpci/vsriov.c b/hypervisor/dm/vpci/vsriov.c index dc1c4c9db6..bf7a6d7808 100644 --- a/hypervisor/dm/vpci/vsriov.c +++ b/hypervisor/dm/vpci/vsriov.c @@ -27,11 +27,11 @@ * $FreeBSD$ */ -#include -#include +#include #include -#include +#include #include +#include #include "vpci_priv.h" diff --git a/hypervisor/dm/vpic.c b/hypervisor/dm/vpic.c index 8a1114241f..4d8ec93832 100644 --- a/hypervisor/dm/vpic.c +++ b/hypervisor/dm/vpic.c @@ -27,12 +27,18 @@ #define pr_prefix "vpic: " -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define DBG_LEVEL_PIC 6U @@ -408,7 +414,8 @@ static int32_t vpic_ocw1(const struct acrn_vpic *vpic, struct i8259_reg_state *i */ if (((i8259->mask & bit) == 0U) && ((old & bit) != 0U)) { uint32_t virt_pin; - uint32_t vgsi; + struct ptintr_add_args intx_add; + struct ptintr_remap_args intx_remap; /* Primary i8259 pin2 connect with secondary i8259, * not device, so not need pt remap @@ -421,8 +428,16 @@ static int32_t vpic_ocw1(const struct acrn_vpic *vpic, struct i8259_reg_state *i virt_pin = (primary_pic(vpic, i8259)) ? pin : (pin + 8U); - vgsi = vpin_to_vgsi(vm, virt_pin); - (void)ptirq_intx_pin_remap(vm, vgsi, INTX_CTLR_PIC); + intx_add.intr_type = PTDEV_INTR_INTX; + intx_add.intx.virt_gsi = vpin_to_vgsi(vm, virt_pin); + intx_add.intx.virt_ctlr = INTX_CTLR_PIC; + intx_add.intx.phys_gsi = intx_add.intx.virt_gsi; + intx_add.intx.phys_ctlr = INTX_CTLR_IOAPIC; + (void)ptintr_add(vm, &intx_add); + intx_remap.intr_type = PTDEV_INTR_INTX; + intx_remap.intx.virt_gsi = vpin_to_vgsi(vm, virt_pin); + intx_remap.intx.virt_ctlr = INTX_CTLR_PIC; + (void)ptintr_remap(vm, &intx_remap); } pin = (pin + 1U) & 0x7U; } @@ -461,7 +476,7 @@ static int32_t vpic_ocw2(const struct acrn_vpic *vpic, struct i8259_reg_state *i /* if level ack PTDEV */ if ((i8259->elc & (1U << (isr_bit & 0x7U))) != 0U) { vgsi = vpin_to_vgsi(vm, (primary_pic(vpic, i8259) ? isr_bit : isr_bit + 8U)); - ptirq_intx_ack(vm, vgsi, INTX_CTLR_PIC); + ptintr_intx_ack(vm, vgsi, INTX_CTLR_PIC); } } else if (((val & OCW2_SL) != 0U) && i8259->rotate) { /* specific priority */ @@ -533,7 +548,7 @@ static void vpic_set_pinstate(struct acrn_vpic *vpic, uint32_t pin, uint8_t leve } /** - * @brief Set vPIC IRQ line status. + * @brief Set vPIC IRQ line status, without acquiring the vPIC lock. * * @param[in] vpic Pointer to virtual pic structure * @param[in] irqline Target IRQ number @@ -542,18 +557,17 @@ static void vpic_set_pinstate(struct acrn_vpic *vpic, uint32_t pin, uint8_t leve * * @return None */ -void vpic_set_irqline(struct acrn_vpic *vpic, uint32_t vgsi, uint32_t operation) +void vpic_set_irqline_nolock(struct acrn_vpic *vpic, uint32_t vgsi, uint32_t operation) { struct i8259_reg_state *i8259; uint32_t pin; - uint64_t rflags; if (vgsi < NR_VPIC_PINS_TOTAL) { i8259 = &vpic->i8259[vgsi >> 3U]; if (i8259->ready) { pin = vgsi_to_vpin(vpic2vm(vpic), vgsi); - spinlock_irqsave_obtain(&(vpic->lock), &rflags); + switch (operation) { case GSI_SET_HIGH: vpic_set_pinstate(vpic, pin, 1U); @@ -576,11 +590,29 @@ void vpic_set_irqline(struct acrn_vpic *vpic, uint32_t vgsi, uint32_t operation) break; } vpic_notify_intr(vpic); - spinlock_irqrestore_release(&(vpic->lock), rflags); } } } +/** + * @brief Set vPIC IRQ line status. + * + * @param[in] vpic Pointer to virtual pic structure + * @param[in] irqline Target IRQ number + * @param[in] operation action options:GSI_SET_HIGH/GSI_SET_LOW/ + * GSI_RAISING_PULSE/GSI_FALLING_PULSE + * + * @return None + */ +void vpic_set_irqline_lock(struct acrn_vpic *vpic, uint32_t vgsi, uint32_t operation) +{ + uint64_t rflags; + + spinlock_irqsave_obtain(&(vpic->lock), &rflags); + vpic_set_irqline_nolock(vpic, vgsi, operation); + spinlock_irqrestore_release(&(vpic->lock), rflags); +} + uint32_t vpic_pincount(void) { diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c index 3979b50cae..bec9dbfd85 100644 --- a/hypervisor/dm/vrtc.c +++ b/hypervisor/dm/vrtc.c @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include +#include +#include #define CMOS_ADDR_PORT 0x70U #define CMOS_DATA_PORT 0x71U diff --git a/hypervisor/dm/vuart.c b/hypervisor/dm/vuart.c index 6671ca61d2..acbaa9ee45 100644 --- a/hypervisor/dm/vuart.c +++ b/hypervisor/dm/vuart.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #define init_vuart_lock(vu) spinlock_init(&((vu)->lock)) @@ -187,7 +187,7 @@ static void vuart_trigger_level_intr(const struct acrn_vuart *vu, bool assert) operation = assert ? GSI_SET_HIGH : GSI_SET_LOW; } - vpic_set_irqline(vm_pic(vu->vm), vu->irq, operation); + vpic_set_irqline_lock(vm_pic(vu->vm), vu->irq, operation); vioapic_set_irqline_lock(vu->vm, vu->irq, operation); } diff --git a/hypervisor/hw/pci.c b/hypervisor/hw/pci.c index 95be86a0bf..f076a3f1e0 100644 --- a/hypervisor/hw/pci.c +++ b/hypervisor/hw/pci.c @@ -32,17 +32,17 @@ * */ #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/hypervisor/include/arch/x86/apicreg.h b/hypervisor/include/arch/x86/apicreg.h index b00b487c80..1a8958acea 100644 --- a/hypervisor/include/arch/x86/apicreg.h +++ b/hypervisor/include/arch/x86/apicreg.h @@ -29,8 +29,6 @@ #ifndef APICREG_H #define APICREG_H -#include - /* * Local && I/O APIC definitions. */ diff --git a/hypervisor/include/arch/x86/board.h b/hypervisor/include/arch/x86/board.h index 427c2544d7..489ab04e77 100644 --- a/hypervisor/include/arch/x86/board.h +++ b/hypervisor/include/arch/x86/board.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/hypervisor/include/arch/x86/cpu.h b/hypervisor/include/arch/x86/cpu.h index 32977a159f..b2f002f866 100644 --- a/hypervisor/include/arch/x86/cpu.h +++ b/hypervisor/include/arch/x86/cpu.h @@ -40,6 +40,9 @@ #include #include +/* TODO: remove from cpu.h */ +#define INVALID_INTERRUPT_PIN 0xffffffffU + /* Define CPU stack alignment */ #define CPU_STACK_ALIGN 16UL @@ -413,6 +416,32 @@ struct cpu_context { struct ext_context ext_ctx; }; +/* + * Definition of the interrupt stack frame layout + */ +struct intr_excp_ctx { + struct acrn_gp_regs gp_regs; + uint64_t vector; + uint64_t error_code; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}; + +void dispatch_exception(struct intr_excp_ctx *ctx); + +/** + * @brief Handle NMI + * + * To handle an NMI + * + * @param ctx Pointer to interrupt exception context + */ + +void handle_nmi(struct intr_excp_ctx *ctx); + /* Function prototypes */ void cpu_do_idle(void); void cpu_dead(void); @@ -683,12 +712,19 @@ static inline void clac(void) asm volatile ("clac" : : : "memory"); } +/* + * @pre num <= MAX_PCPU_NUM + */ +void set_pcpu_nums(uint16_t num); /* * @post return <= MAX_PCPU_NUM */ uint16_t get_pcpu_nums(void); bool is_pcpu_active(uint16_t pcpu_id); uint64_t get_active_pcpu_bitmap(void); +void wait_all_pcpus_run(void); +void set_active_pcpu_bitmap(uint16_t pcpu_id); +void pcpu_set_current_state(uint16_t pcpu_id, enum pcpu_boot_state state); #else /* ASSEMBLER defined */ #endif /* ASSEMBLER defined */ diff --git a/hypervisor/include/arch/x86/cpu_caps.h b/hypervisor/include/arch/x86/cpu_caps.h index ba7a9b6c91..4e11ff6701 100644 --- a/hypervisor/include/arch/x86/cpu_caps.h +++ b/hypervisor/include/arch/x86/cpu_caps.h @@ -31,32 +31,113 @@ #define FEAT_D_1_EDX 14U /* CPUID[D][1].EDX */ #define FEATURE_WORDS 15U -struct cpuinfo_x86 { - /* SDM 2-2 Vol.4 Table 2-1 uses DisplayFamily_DisplayModel to - * distinguish Processor Families/Processor Number Series. - */ - uint8_t displayfamily, displaymodel; - uint8_t virt_bits; - uint8_t phys_bits; - uint32_t cpuid_level; - uint32_t extended_cpuid_level; - uint64_t physical_address_mask; - uint32_t cpuid_leaves[FEATURE_WORDS]; - char model_name[64]; -}; +/* Intel-defined CPU features, CPUID level 0x00000001 (ECX)*/ +#define X86_FEATURE_SSE3 ((FEAT_1_ECX << 5U) + 0U) +#define X86_FEATURE_PCLMUL ((FEAT_1_ECX << 5U) + 1U) +#define X86_FEATURE_DTES64 ((FEAT_1_ECX << 5U) + 2U) +#define X86_FEATURE_MONITOR ((FEAT_1_ECX << 5U) + 3U) +#define X86_FEATURE_DS_CPL ((FEAT_1_ECX << 5U) + 4U) +#define X86_FEATURE_VMX ((FEAT_1_ECX << 5U) + 5U) +#define X86_FEATURE_SMX ((FEAT_1_ECX << 5U) + 6U) +#define X86_FEATURE_EST ((FEAT_1_ECX << 5U) + 7U) +#define X86_FEATURE_TM2 ((FEAT_1_ECX << 5U) + 8U) +#define X86_FEATURE_SSSE3 ((FEAT_1_ECX << 5U) + 9U) +#define X86_FEATURE_CID ((FEAT_1_ECX << 5U) + 10U) +#define X86_FEATURE_FMA ((FEAT_1_ECX << 5U) + 12U) +#define X86_FEATURE_CX16 ((FEAT_1_ECX << 5U) + 13U) +#define X86_FEATURE_ETPRD ((FEAT_1_ECX << 5U) + 14U) +#define X86_FEATURE_PDCM ((FEAT_1_ECX << 5U) + 15U) +#define X86_FEATURE_PCID ((FEAT_1_ECX << 5U) + 17U) +#define X86_FEATURE_DCA ((FEAT_1_ECX << 5U) + 18U) +#define X86_FEATURE_SSE4_1 ((FEAT_1_ECX << 5U) + 19U) +#define X86_FEATURE_SSE4_2 ((FEAT_1_ECX << 5U) + 20U) +#define X86_FEATURE_X2APIC ((FEAT_1_ECX << 5U) + 21U) +#define X86_FEATURE_MOVBE ((FEAT_1_ECX << 5U) + 22U) +#define X86_FEATURE_POPCNT ((FEAT_1_ECX << 5U) + 23U) +#define X86_FEATURE_TSC_DEADLINE ((FEAT_1_ECX << 5U) + 24U) +#define X86_FEATURE_AES ((FEAT_1_ECX << 5U) + 25U) +#define X86_FEATURE_XSAVE ((FEAT_1_ECX << 5U) + 26U) +#define X86_FEATURE_OSXSAVE ((FEAT_1_ECX << 5U) + 27U) +#define X86_FEATURE_AVX ((FEAT_1_ECX << 5U) + 28U) + +/* Intel-defined CPU features, CPUID level 0x00000001 (EDX)*/ +#define X86_FEATURE_FPU ((FEAT_1_EDX << 5U) + 0U) +#define X86_FEATURE_VME ((FEAT_1_EDX << 5U) + 1U) +#define X86_FEATURE_DE ((FEAT_1_EDX << 5U) + 2U) +#define X86_FEATURE_PSE ((FEAT_1_EDX << 5U) + 3U) +#define X86_FEATURE_TSC ((FEAT_1_EDX << 5U) + 4U) +#define X86_FEATURE_MSR ((FEAT_1_EDX << 5U) + 5U) +#define X86_FEATURE_PAE ((FEAT_1_EDX << 5U) + 6U) +#define X86_FEATURE_MCE ((FEAT_1_EDX << 5U) + 7U) +#define X86_FEATURE_CX8 ((FEAT_1_EDX << 5U) + 8U) +#define X86_FEATURE_APIC ((FEAT_1_EDX << 5U) + 9U) +#define X86_FEATURE_SEP ((FEAT_1_EDX << 5U) + 11U) +#define X86_FEATURE_MTRR ((FEAT_1_EDX << 5U) + 12U) +#define X86_FEATURE_PGE ((FEAT_1_EDX << 5U) + 13U) +#define X86_FEATURE_MCA ((FEAT_1_EDX << 5U) + 14U) +#define X86_FEATURE_CMOV ((FEAT_1_EDX << 5U) + 15U) +#define X86_FEATURE_PAT ((FEAT_1_EDX << 5U) + 16U) +#define X86_FEATURE_PSE36 ((FEAT_1_EDX << 5U) + 17U) +#define X86_FEATURE_PSN ((FEAT_1_EDX << 5U) + 18U) +#define X86_FEATURE_CLF ((FEAT_1_EDX << 5U) + 19U) +#define X86_FEATURE_DTES ((FEAT_1_EDX << 5U) + 21U) +#define X86_FEATURE_ACPI ((FEAT_1_EDX << 5U) + 22U) +#define X86_FEATURE_MMX ((FEAT_1_EDX << 5U) + 23U) +#define X86_FEATURE_FXSR ((FEAT_1_EDX << 5U) + 24U) +#define X86_FEATURE_SSE ((FEAT_1_EDX << 5U) + 25U) +#define X86_FEATURE_SSE2 ((FEAT_1_EDX << 5U) + 26U) +#define X86_FEATURE_SS ((FEAT_1_EDX << 5U) + 27U) +#define X86_FEATURE_HTT ((FEAT_1_EDX << 5U) + 28U) +#define X86_FEATURE_TM1 ((FEAT_1_EDX << 5U) + 29U) +#define X86_FEATURE_IA64 ((FEAT_1_EDX << 5U) + 30U) +#define X86_FEATURE_PBE ((FEAT_1_EDX << 5U) + 31U) + +/* Intel-defined CPU features, CPUID level 0x00000007 (EBX)*/ +#define X86_FEATURE_TSC_ADJ ((FEAT_7_0_EBX << 5U) + 1U) +#define X86_FEATURE_SGX ((FEAT_7_0_EBX << 5U) + 2U) +#define X86_FEATURE_SMEP ((FEAT_7_0_EBX << 5U) + 7U) +#define X86_FEATURE_ERMS ((FEAT_7_0_EBX << 5U) + 9U) +#define X86_FEATURE_INVPCID ((FEAT_7_0_EBX << 5U) + 10U) +#define X86_FEATURE_RDT_A ((FEAT_7_0_EBX << 5U) + 15U) +#define X86_FEATURE_SMAP ((FEAT_7_0_EBX << 5U) + 20U) +#define X86_FEATURE_CLFLUSHOPT ((FEAT_7_0_EBX << 5U) + 23U) + +/* Intel-defined CPU features, CPUID level 0x00000007 (EDX)*/ +#define X86_FEATURE_MDS_CLEAR ((FEAT_7_0_EDX << 5U) + 10U) +#define X86_FEATURE_IBRS_IBPB ((FEAT_7_0_EDX << 5U) + 26U) +#define X86_FEATURE_STIBP ((FEAT_7_0_EDX << 5U) + 27U) +#define X86_FEATURE_L1D_FLUSH ((FEAT_7_0_EDX << 5U) + 28U) +#define X86_FEATURE_ARCH_CAP ((FEAT_7_0_EDX << 5U) + 29U) +#define X86_FEATURE_CORE_CAP ((FEAT_7_0_EDX << 5U) + 30U) +#define X86_FEATURE_SSBD ((FEAT_7_0_EDX << 5U) + 31U) + +/* Intel-defined CPU features, CPUID level 0x80000001 (EDX)*/ +#define X86_FEATURE_NX ((FEAT_8000_0001_EDX << 5U) + 20U) +#define X86_FEATURE_PAGE1GB ((FEAT_8000_0001_EDX << 5U) + 26U) +#define X86_FEATURE_LM ((FEAT_8000_0001_EDX << 5U) + 29U) + +/* Intel-defined CPU features, CPUID level 0x80000007 (EDX)*/ +#define X86_FEATURE_INVA_TSC ((FEAT_8000_0007_EDX << 5U) + 8U) + +/* Intel-defined CPU features, CPUID level 0x0000000D, sub 0x1 */ +#define X86_FEATURE_COMPACTION_EXT ((FEAT_D_1_EAX << 5U) + 1U) +#define X86_FEATURE_XSAVES ((FEAT_D_1_EAX << 5U) + 3U) bool has_monitor_cap(void); -bool is_apl_platform(void); +uint8_t pcpu_family_id(void); +uint8_t pcpu_model_id(void); +char *pcpu_model_name(void); bool is_apicv_advanced_feature_supported(void); +uint8_t pcpu_physaddr_bits(void); +uint8_t pcpu_virtaddr_bits(void); +uint32_t pcpu_cpuid_level(void); +bool pcpu_set_cap(uint32_t bit); bool pcpu_has_cap(uint32_t bit); bool pcpu_has_vmx_ept_cap(uint32_t bit_mask); bool pcpu_has_vmx_vpid_cap(uint32_t bit_mask); -bool is_apl_platform(void); bool has_core_cap(uint32_t bit_mask); bool is_ac_enabled(void); void init_pcpu_capabilities(void); -void init_pcpu_model_name(void); int32_t detect_hardware_support(void); -struct cpuinfo_x86 *get_pcpu_info(void); #endif /* CPUINFO_H */ diff --git a/hypervisor/include/arch/x86/cpufeatures.h b/hypervisor/include/arch/x86/cpufeatures.h deleted file mode 100644 index e865b00b17..0000000000 --- a/hypervisor/include/arch/x86/cpufeatures.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef CPUFEATURES_H -#define CPUFEATURES_H - -/* Intel-defined CPU features, CPUID level 0x00000001 (ECX)*/ -#define X86_FEATURE_SSE3 ((FEAT_1_ECX << 5U) + 0U) -#define X86_FEATURE_PCLMUL ((FEAT_1_ECX << 5U) + 1U) -#define X86_FEATURE_DTES64 ((FEAT_1_ECX << 5U) + 2U) -#define X86_FEATURE_MONITOR ((FEAT_1_ECX << 5U) + 3U) -#define X86_FEATURE_DS_CPL ((FEAT_1_ECX << 5U) + 4U) -#define X86_FEATURE_VMX ((FEAT_1_ECX << 5U) + 5U) -#define X86_FEATURE_SMX ((FEAT_1_ECX << 5U) + 6U) -#define X86_FEATURE_EST ((FEAT_1_ECX << 5U) + 7U) -#define X86_FEATURE_TM2 ((FEAT_1_ECX << 5U) + 8U) -#define X86_FEATURE_SSSE3 ((FEAT_1_ECX << 5U) + 9U) -#define X86_FEATURE_CID ((FEAT_1_ECX << 5U) + 10U) -#define X86_FEATURE_FMA ((FEAT_1_ECX << 5U) + 12U) -#define X86_FEATURE_CX16 ((FEAT_1_ECX << 5U) + 13U) -#define X86_FEATURE_ETPRD ((FEAT_1_ECX << 5U) + 14U) -#define X86_FEATURE_PDCM ((FEAT_1_ECX << 5U) + 15U) -#define X86_FEATURE_PCID ((FEAT_1_ECX << 5U) + 17U) -#define X86_FEATURE_DCA ((FEAT_1_ECX << 5U) + 18U) -#define X86_FEATURE_SSE4_1 ((FEAT_1_ECX << 5U) + 19U) -#define X86_FEATURE_SSE4_2 ((FEAT_1_ECX << 5U) + 20U) -#define X86_FEATURE_X2APIC ((FEAT_1_ECX << 5U) + 21U) -#define X86_FEATURE_MOVBE ((FEAT_1_ECX << 5U) + 22U) -#define X86_FEATURE_POPCNT ((FEAT_1_ECX << 5U) + 23U) -#define X86_FEATURE_TSC_DEADLINE ((FEAT_1_ECX << 5U) + 24U) -#define X86_FEATURE_AES ((FEAT_1_ECX << 5U) + 25U) -#define X86_FEATURE_XSAVE ((FEAT_1_ECX << 5U) + 26U) -#define X86_FEATURE_OSXSAVE ((FEAT_1_ECX << 5U) + 27U) -#define X86_FEATURE_AVX ((FEAT_1_ECX << 5U) + 28U) - -/* Intel-defined CPU features, CPUID level 0x00000001 (EDX)*/ -#define X86_FEATURE_FPU ((FEAT_1_EDX << 5U) + 0U) -#define X86_FEATURE_VME ((FEAT_1_EDX << 5U) + 1U) -#define X86_FEATURE_DE ((FEAT_1_EDX << 5U) + 2U) -#define X86_FEATURE_PSE ((FEAT_1_EDX << 5U) + 3U) -#define X86_FEATURE_TSC ((FEAT_1_EDX << 5U) + 4U) -#define X86_FEATURE_MSR ((FEAT_1_EDX << 5U) + 5U) -#define X86_FEATURE_PAE ((FEAT_1_EDX << 5U) + 6U) -#define X86_FEATURE_MCE ((FEAT_1_EDX << 5U) + 7U) -#define X86_FEATURE_CX8 ((FEAT_1_EDX << 5U) + 8U) -#define X86_FEATURE_APIC ((FEAT_1_EDX << 5U) + 9U) -#define X86_FEATURE_SEP ((FEAT_1_EDX << 5U) + 11U) -#define X86_FEATURE_MTRR ((FEAT_1_EDX << 5U) + 12U) -#define X86_FEATURE_PGE ((FEAT_1_EDX << 5U) + 13U) -#define X86_FEATURE_MCA ((FEAT_1_EDX << 5U) + 14U) -#define X86_FEATURE_CMOV ((FEAT_1_EDX << 5U) + 15U) -#define X86_FEATURE_PAT ((FEAT_1_EDX << 5U) + 16U) -#define X86_FEATURE_PSE36 ((FEAT_1_EDX << 5U) + 17U) -#define X86_FEATURE_PSN ((FEAT_1_EDX << 5U) + 18U) -#define X86_FEATURE_CLF ((FEAT_1_EDX << 5U) + 19U) -#define X86_FEATURE_DTES ((FEAT_1_EDX << 5U) + 21U) -#define X86_FEATURE_ACPI ((FEAT_1_EDX << 5U) + 22U) -#define X86_FEATURE_MMX ((FEAT_1_EDX << 5U) + 23U) -#define X86_FEATURE_FXSR ((FEAT_1_EDX << 5U) + 24U) -#define X86_FEATURE_SSE ((FEAT_1_EDX << 5U) + 25U) -#define X86_FEATURE_SSE2 ((FEAT_1_EDX << 5U) + 26U) -#define X86_FEATURE_SS ((FEAT_1_EDX << 5U) + 27U) -#define X86_FEATURE_HTT ((FEAT_1_EDX << 5U) + 28U) -#define X86_FEATURE_TM1 ((FEAT_1_EDX << 5U) + 29U) -#define X86_FEATURE_IA64 ((FEAT_1_EDX << 5U) + 30U) -#define X86_FEATURE_PBE ((FEAT_1_EDX << 5U) + 31U) - -/* Intel-defined CPU features, CPUID level 0x00000007 (EBX)*/ -#define X86_FEATURE_TSC_ADJ ((FEAT_7_0_EBX << 5U) + 1U) -#define X86_FEATURE_SGX ((FEAT_7_0_EBX << 5U) + 2U) -#define X86_FEATURE_SMEP ((FEAT_7_0_EBX << 5U) + 7U) -#define X86_FEATURE_ERMS ((FEAT_7_0_EBX << 5U) + 9U) -#define X86_FEATURE_INVPCID ((FEAT_7_0_EBX << 5U) + 10U) -#define X86_FEATURE_RDT_A ((FEAT_7_0_EBX << 5U) + 15U) -#define X86_FEATURE_SMAP ((FEAT_7_0_EBX << 5U) + 20U) -#define X86_FEATURE_CLFLUSHOPT ((FEAT_7_0_EBX << 5U) + 23U) - -/* Intel-defined CPU features, CPUID level 0x00000007 (EDX)*/ -#define X86_FEATURE_MDS_CLEAR ((FEAT_7_0_EDX << 5U) + 10U) -#define X86_FEATURE_IBRS_IBPB ((FEAT_7_0_EDX << 5U) + 26U) -#define X86_FEATURE_STIBP ((FEAT_7_0_EDX << 5U) + 27U) -#define X86_FEATURE_L1D_FLUSH ((FEAT_7_0_EDX << 5U) + 28U) -#define X86_FEATURE_ARCH_CAP ((FEAT_7_0_EDX << 5U) + 29U) -#define X86_FEATURE_CORE_CAP ((FEAT_7_0_EDX << 5U) + 30U) -#define X86_FEATURE_SSBD ((FEAT_7_0_EDX << 5U) + 31U) - -/* Intel-defined CPU features, CPUID level 0x80000001 (EDX)*/ -#define X86_FEATURE_NX ((FEAT_8000_0001_EDX << 5U) + 20U) -#define X86_FEATURE_PAGE1GB ((FEAT_8000_0001_EDX << 5U) + 26U) -#define X86_FEATURE_LM ((FEAT_8000_0001_EDX << 5U) + 29U) - -/* Intel-defined CPU features, CPUID level 0x80000007 (EDX)*/ -#define X86_FEATURE_INVA_TSC ((FEAT_8000_0007_EDX << 5U) + 8U) - -/* Intel-defined CPU features, CPUID level 0x0000000D, sub 0x1 */ -#define X86_FEATURE_COMPACTION_EXT ((FEAT_D_1_EAX << 5U) + 1U) -#define X86_FEATURE_XSAVES ((FEAT_D_1_EAX << 5U) + 3U) - -#endif /* CPUFEATURES_H */ diff --git a/hypervisor/include/arch/x86/gdt.h b/hypervisor/include/arch/x86/gdt.h index d40b32bf7c..a0d08c2e8d 100644 --- a/hypervisor/include/arch/x86/gdt.h +++ b/hypervisor/include/arch/x86/gdt.h @@ -69,7 +69,7 @@ #ifndef ASSEMBLER #include -#include +#include #define TSS_AVAIL (9U) diff --git a/hypervisor/include/arch/x86/guest/assign.h b/hypervisor/include/arch/x86/guest/assign.h deleted file mode 100644 index b054152d58..0000000000 --- a/hypervisor/include/arch/x86/guest/assign.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ASSIGN_H -#define ASSIGN_H - -#include -#include - -/** - * @file assign.h - * - * @brief public APIs for Passthrough Interrupt Remapping - */ - -/** - * @brief VT-d - * - * @defgroup acrn_passthrough ACRN Passthrough - * @{ - */ - -/** - * @brief Acknowledge a virtual interrupt for passthrough device. - * - * Acknowledge a virtual legacy interrupt for a passthrough device. - * - * @param[in] vm pointer to acrn_vm - * @param[in] virt_gsi virtual GSI number associated with the passthrough device - * @param[in] vgsi_ctlr INTX_CTLR_IOAPIC or INTX_CTLR_PIC - * - * @return None - * - * @pre vm != NULL - * - */ -void ptirq_intx_ack(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_ctlr); - -/** - * @brief MSI/MSI-x remapping for passthrough device. - * - * Main entry for PCI device assignment with MSI and MSI-X. - * MSI can up to 8 vectors and MSI-X can up to 1024 Vectors. - * - * @param[in] vm pointer to acrn_vm - * @param[in] virt_bdf virtual bdf associated with the passthrough device - * @param[in] phys_bdf virtual bdf associated with the passthrough device - * @param[in] entry_nr indicate coming vectors, entry_nr = 0 means first vector - * @param[in] info structure used for MSI/MSI-x remapping - * @param[in] irte_idx caller can pass a valid IRTE index, otherwise, use INVALID_IRTE_ID - * - * @return - * - 0: on success - * - \p -ENODEV: - * - for SOS, the entry already be held by others - * - for UOS, no pre-hold mapping found. - * - * @pre vm != NULL - * @pre info != NULL - * - */ -int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t phys_bdf, - uint16_t entry_nr, struct msi_info *info, uint16_t irte_idx); - - -/** - * @brief INTx remapping for passthrough device. - * - * Set up the remapping of the given virtual pin for the given vm. - * This is the main entry for PCI/Legacy device assignment with INTx, calling from vIOAPIC or vPIC. - * - * @param[in] vm pointer to acrn_vm - * @param[in] virt_gsi virtual GSI number associated with the passthrough device - * @param[in] vgsi_ctlr INTX_CTLR_IOAPIC or INTX_CTLR_PIC - * - * @return - * - 0: on success - * - \p -ENODEV: - * - for SOS, the entry already be held by others - * - for UOS, no pre-hold mapping found. - * - * @pre vm != NULL - * - */ -int32_t ptirq_intx_pin_remap(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_ctlr); - -/** - * @brief Add an interrupt remapping entry for INTx as pre-hold mapping. - * - * Except sos_vm, Device Model should call this function to pre-hold ptdev intx - * The entry is identified by phys_pin, one entry vs. one phys_pin. - * Currently, one phys_pin can only be held by one pin source (vPIC or vIOAPIC). - * - * @param[in] vm pointer to acrn_vm - * @param[in] virt_gsi virtual pin number associated with the passthrough device - * @param[in] phys_gsi physical pin number associated with the passthrough device - * @param[in] pic_pin true for pic, false for ioapic - * - * @return - * - 0: on success - * - \p -EINVAL: invalid virt_pin value - * - \p -ENODEV: failed to add the remapping entry - * - * @pre vm != NULL - * - */ -int32_t ptirq_add_intx_remapping(struct acrn_vm *vm, uint32_t virt_gsi, uint32_t phys_gsi, bool pic_pin); - -/** - * @brief Remove an interrupt remapping entry for INTx. - * - * Deactivate & remove mapping entry of the given virt_pin for given vm. - * - * @param[in] vm pointer to acrn_vm - * @param[in] virt_gsi virtual pin number associated with the passthrough device - * @param[in] pic_pin true for pic, false for ioapic - * - * @return None - * - * @pre vm != NULL - * - */ -void ptirq_remove_intx_remapping(const struct acrn_vm *vm, uint32_t virt_gsi, bool pic_pin); - -/** - * @brief Remove interrupt remapping entry/entries for MSI/MSI-x. - * - * Remove the mapping of given number of vectors of the given virtual BDF for the given vm. - * - * @param[in] vm pointer to acrn_vm - * @param[in] phys_bdf physical bdf associated with the passthrough device - * @param[in] vector_count number of vectors - * - * @return None - * - * @pre vm != NULL - * - */ -void ptirq_remove_msix_remapping(const struct acrn_vm *vm, uint16_t phys_bdf, uint32_t vector_count); - -/** - * @brief Remove all interrupt remappings for INTx which are defined in VM config. - * - * Deactivate & remove all mapping entries of the virt_gsis defined in VM config for given vm. - * - * @param[in] vm pointer to acrn_vm - * - * @return None - * - * @pre vm != NULL - * - */ -void ptirq_remove_configured_intx_remappings(const struct acrn_vm *vm); - -/** - * @} - */ - -#endif /* ASSIGN_H */ diff --git a/hypervisor/include/arch/x86/guest/hyperv.h b/hypervisor/include/arch/x86/guest/hyperv.h index 32515748b6..d448e3c0c0 100644 --- a/hypervisor/include/arch/x86/guest/hyperv.h +++ b/hypervisor/include/arch/x86/guest/hyperv.h @@ -7,7 +7,7 @@ #ifndef HYPERV_H #define HYPERV_H -#include +#include /* Hyper-V MSR numbers */ #define HV_X64_MSR_GUEST_OS_ID 0x40000000U diff --git a/hypervisor/include/arch/x86/guest/instr_emul.h b/hypervisor/include/arch/x86/guest/instr_emul.h index e71dd6f787..1272a2655e 100644 --- a/hypervisor/include/arch/x86/guest/instr_emul.h +++ b/hypervisor/include/arch/x86/guest/instr_emul.h @@ -31,8 +31,8 @@ #define INSTR_EMUL_H #include -#include -#include +#include +#include struct acrn_vcpu; struct instr_emul_vie_op { diff --git a/hypervisor/include/arch/x86/guest/trusty.h b/hypervisor/include/arch/x86/guest/trusty.h index 46c21d31f9..b1cca1e634 100644 --- a/hypervisor/include/arch/x86/guest/trusty.h +++ b/hypervisor/include/arch/x86/guest/trusty.h @@ -7,7 +7,7 @@ #ifndef TRUSTY_H_ #define TRUSTY_H_ #include -#include +#include #define RPMB_MAX_PARTITION_NUMBER 6U #define MMC_PROD_NAME_WITH_PSN_LEN 15U diff --git a/hypervisor/include/arch/x86/guest/vcpu.h b/hypervisor/include/arch/x86/guest/vcpu.h index 5ff9336cdd..0e7b4cadd5 100644 --- a/hypervisor/include/arch/x86/guest/vcpu.h +++ b/hypervisor/include/arch/x86/guest/vcpu.h @@ -17,17 +17,17 @@ #ifndef ASSEMBLER #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include /** * @brief vcpu diff --git a/hypervisor/include/arch/x86/guest/virq.h b/hypervisor/include/arch/x86/guest/virq.h new file mode 100644 index 0000000000..a5ec0f9985 --- /dev/null +++ b/hypervisor/include/arch/x86/guest/virq.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef VIRQ_H +#define VIRQ_H + +struct acrn_vcpu; +struct acrn_vm; + +/** + * @brief virtual IRQ + * + * @addtogroup acrn_virq ACRN vIRQ + * @{ + */ + +/** + * @brief Queue exception to guest. + * + * This exception may be injected immediately or later, + * depends on the exeception class. + * + * @param[in] vcpu Pointer to vCPU. + * @param[in] vector_arg Vector of the exeception. + * @param[in] err_code_arg Error Code to be injected. + * + * @retval 0 on success + * @retval -EINVAL on error that vector is invalid. + * + * @pre vcpu != NULL + */ +int32_t vcpu_queue_exception(struct acrn_vcpu *vcpu, uint32_t vector_arg, uint32_t err_code_arg); + +/** + * @brief Inject external interrupt to guest. + * + * @param[in] vcpu Pointer to vCPU. + * + * @return None + * + * @pre vcpu != NULL + */ +void vcpu_inject_extint(struct acrn_vcpu *vcpu); + +/** + * @brief Inject NMI to guest. + * + * @param[in] vcpu Pointer to vCPU. + * + * @return None + * + * @pre vcpu != NULL + */ +void vcpu_inject_nmi(struct acrn_vcpu *vcpu); + +/** + * @brief Inject general protection exeception(GP) to guest. + * + * @param[in] vcpu Pointer to vCPU. + * @param[in] err_code Error Code to be injected. + * + * @return None + * + * @pre vcpu != NULL + */ +void vcpu_inject_gp(struct acrn_vcpu *vcpu, uint32_t err_code); + +/** + * @brief Inject page fault exeception(PF) to guest. + * + * @param[in] vcpu Pointer to vCPU. + * @param[in] addr Address that result in PF. + * @param[in] err_code Error Code to be injected. + * + * @return None + * + * @pre vcpu != NULL + */ +void vcpu_inject_pf(struct acrn_vcpu *vcpu, uint64_t addr, uint32_t err_code); + +/** + * @brief Inject invalid opcode exeception(UD) to guest. + * + * @param[in] vcpu Pointer to vCPU. + * + * @return None + * + * @pre vcpu != NULL + */ +void vcpu_inject_ud(struct acrn_vcpu *vcpu); + +/** + * @brief Inject stack fault exeception(SS) to guest. + * + * @param[in] vcpu Pointer to vCPU. + * + * @return None + * + * @pre vcpu != NULL + */ +void vcpu_inject_ss(struct acrn_vcpu *vcpu); +void vcpu_make_request(struct acrn_vcpu *vcpu, uint16_t eventid); + +/* + * @pre vcpu != NULL + */ +int32_t exception_vmexit_handler(struct acrn_vcpu *vcpu); +int32_t nmi_window_vmexit_handler(struct acrn_vcpu *vcpu); +int32_t interrupt_window_vmexit_handler(struct acrn_vcpu *vcpu); +int32_t external_interrupt_vmexit_handler(struct acrn_vcpu *vcpu); +int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu); + +#endif diff --git a/hypervisor/include/arch/x86/guest/vlapic.h b/hypervisor/include/arch/x86/guest/vlapic.h index 1ec99e320d..bec42d7f37 100644 --- a/hypervisor/include/arch/x86/guest/vlapic.h +++ b/hypervisor/include/arch/x86/guest/vlapic.h @@ -30,9 +30,9 @@ #ifndef VLAPIC_H #define VLAPIC_H -#include +#include #include -#include +#include /** * @file vlapic.h diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 9994295dd1..d44dfbe6c4 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -13,21 +13,21 @@ #ifndef ASSEMBLER -#include -#include -#include +#include +#include +#include #include #include -#include +#include #include -#include -#include +#include +#include #include -#include -#include -#include +#include +#include +#include #ifdef CONFIG_HYPERV_ENABLED -#include +#include #endif enum reset_mode { diff --git a/hypervisor/include/arch/x86/guest/vmcs.h b/hypervisor/include/arch/x86/guest/vmcs.h index 752946f57a..a33b38a6c7 100644 --- a/hypervisor/include/arch/x86/guest/vmcs.h +++ b/hypervisor/include/arch/x86/guest/vmcs.h @@ -12,7 +12,7 @@ #ifndef ASSEMBLER #include -#include +#include #define VMX_VMENTRY_FAIL 0x80000000U diff --git a/hypervisor/include/arch/x86/ioapic.h b/hypervisor/include/arch/x86/ioapic.h index a96ccaa70c..1692c17b1c 100644 --- a/hypervisor/include/arch/x86/ioapic.h +++ b/hypervisor/include/arch/x86/ioapic.h @@ -7,8 +7,6 @@ #ifndef IOAPIC_H #define IOAPIC_H -#include - #define NR_LEGACY_IRQ 16U #define NR_LEGACY_PIN NR_LEGACY_IRQ @@ -20,6 +18,7 @@ struct ioapic_info { }; void ioapic_setup_irqs(void); +void init_ioapic(); bool is_ioapic_irq(uint32_t irq); uint32_t gsi_to_ioapic_pin(uint32_t gsi); @@ -27,6 +26,7 @@ int32_t init_ioapic_id_info(void); uint8_t ioapic_irq_to_ioapic_id(uint32_t irq); uint8_t get_platform_ioapic_info (struct ioapic_info **plat_ioapic_info); +void ioapic_get_rte_entry(void *ioapic_base, uint32_t pin, union ioapic_rte *rte); /** * @defgroup ioapic_ext_apis IOAPIC External Interfaces @@ -90,24 +90,6 @@ void ioapic_gsi_unmask_irq(uint32_t irq); void ioapic_get_rte_entry(void *ioapic_base, uint32_t pin, union ioapic_rte *rte); -/* - * is_valid is by default false when all the - * static variables, part of .bss, are initialized to 0s - * It is set to true, if the corresponding - * gsi falls in ranges identified by IOAPIC data - * in ACPI MADT in ioapic_setup_irqs. - */ - -struct gsi_table { - bool is_valid; - struct { - uint8_t acpi_id; - uint8_t index; - uint32_t pin; - void *base_addr; - } ioapic_info; -}; - void *gsi_to_ioapic_base(uint32_t gsi); uint32_t get_max_nr_gsi(void); uint8_t get_gsi_to_ioapic_index(uint32_t gsi); diff --git a/hypervisor/include/arch/x86/irq.h b/hypervisor/include/arch/x86/irq.h index 0d113724e6..0d5f3e1a60 100644 --- a/hypervisor/include/arch/x86/irq.h +++ b/hypervisor/include/arch/x86/irq.h @@ -7,23 +7,20 @@ #ifndef ARCH_IRQ_H #define ARCH_IRQ_H -#include -#include -#include - /** * @file arch/x86/irq.h * - * @brief public APIs for virtual IRQ + * @brief public APIs for arch IRQ */ -#define DBG_LEVEL_PTIRQ 6U -#define DBG_LEVEL_IRQ 6U - #define NR_MAX_VECTOR 0xFFU #define VECTOR_INVALID (NR_MAX_VECTOR + 1U) -#define NR_IRQS 256U -#define IRQ_INVALID 0xffffffffU + +#define HYPERVISOR_CALLBACK_VHM_VECTOR 0xF3U + +#define TIMER_IRQ (NR_IRQS - 1U) +#define NOTIFY_VCPU_IRQ (NR_IRQS - 2U) +#define PMI_IRQ (NR_IRQS - 3U) /* # of NR_STATIC_MAPPINGS_1 entries for timer, vcpu notify, and PMI */ #define NR_STATIC_MAPPINGS_1 3U @@ -44,8 +41,6 @@ */ #define NR_STATIC_MAPPINGS (NR_STATIC_MAPPINGS_1 + CONFIG_MAX_VM_NUM) -#define HYPERVISOR_CALLBACK_VHM_VECTOR 0xF3U - /* vectors range for dynamic allocation, usually for devices */ #define VECTOR_DYNAMIC_START 0x20U #define VECTOR_DYNAMIC_END 0xDFU @@ -64,9 +59,6 @@ */ #define POSTED_INTR_VECTOR (VECTOR_FIXED_START + NR_STATIC_MAPPINGS_1) -#define TIMER_IRQ (NR_IRQS - 1U) -#define NOTIFY_VCPU_IRQ (NR_IRQS - 2U) -#define PMI_IRQ (NR_IRQS - 3U) /* * Starting IRQ for posted interrupts * # of CONFIG_MAX_VM_NUM (POSTED_INTR_IRQ ~ (POSTED_INTR_IRQ + CONFIG_MAX_VM_NUM - 1U)) @@ -74,193 +66,8 @@ */ #define POSTED_INTR_IRQ (NR_IRQS - NR_STATIC_MAPPINGS_1 - CONFIG_MAX_VM_NUM) -/* the maximum number of msi entry is 2048 according to PCI - * local bus specification - */ -#define MAX_MSI_ENTRY 0x800U - -#define DEFAULT_DEST_MODE IOAPIC_RTE_DESTMODE_LOGICAL -#define DEFAULT_DELIVERY_MODE IOAPIC_RTE_DELMODE_LOPRI - -#define IRQ_ALLOC_BITMAP_SIZE INT_DIV_ROUNDUP(NR_IRQS, 64U) - -#define INVALID_INTERRUPT_PIN 0xffffffffU - -#define IRQF_NONE (0U) -#define IRQF_LEVEL (1U << 1U) /* 1: level trigger; 0: edge trigger */ -#define IRQF_PT (1U << 2U) /* 1: for passthrough dev */ - -struct acrn_vcpu; -struct acrn_vm; - -/* - * Definition of the stack frame layout - */ -struct intr_excp_ctx { - struct acrn_gp_regs gp_regs; - uint64_t vector; - uint64_t error_code; - uint64_t rip; - uint64_t cs; - uint64_t rflags; - uint64_t rsp; - uint64_t ss; -}; - -typedef void (*smp_call_func_t)(void *data); -struct smp_call_info_data { - smp_call_func_t func; - void *data; -}; - -void smp_call_function(uint64_t mask, smp_call_func_t func, void *data); -bool is_notification_nmi(const struct acrn_vm *vm); - -void init_default_irqs(uint16_t cpu_id); - -void dispatch_exception(struct intr_excp_ctx *ctx); - -void setup_notification(void); -void setup_pi_notification(void); - -typedef void (*spurious_handler_t)(uint32_t vector); -extern spurious_handler_t spurious_handler; - -uint32_t alloc_irq_num(uint32_t req_irq); -uint32_t alloc_irq_vector(uint32_t irq); - -/* RFLAGS */ -#define HV_ARCH_VCPU_RFLAGS_TF (1UL<<8U) -#define HV_ARCH_VCPU_RFLAGS_IF (1UL<<9U) -#define HV_ARCH_VCPU_RFLAGS_RF (1UL<<16U) - -/* Interruptability State info */ - -#define HV_ARCH_VCPU_BLOCKED_BY_NMI (1UL<<3U) -#define HV_ARCH_VCPU_BLOCKED_BY_MOVSS (1UL<<1U) -#define HV_ARCH_VCPU_BLOCKED_BY_STI (1UL<<0U) - -/** - * @brief virtual IRQ - * - * @addtogroup acrn_virq ACRN vIRQ - * @{ - */ - -/** - * @brief Queue exception to guest. - * - * This exception may be injected immediately or later, - * depends on the exeception class. - * - * @param[in] vcpu Pointer to vCPU. - * @param[in] vector_arg Vector of the exeception. - * @param[in] err_code_arg Error Code to be injected. - * - * @retval 0 on success - * @retval -EINVAL on error that vector is invalid. - * - * @pre vcpu != NULL - */ -int32_t vcpu_queue_exception(struct acrn_vcpu *vcpu, uint32_t vector_arg, uint32_t err_code_arg); - -/** - * @brief Inject external interrupt to guest. - * - * @param[in] vcpu Pointer to vCPU. - * - * @return None - * - * @pre vcpu != NULL - */ -void vcpu_inject_extint(struct acrn_vcpu *vcpu); - -/** - * @brief Inject NMI to guest. - * - * @param[in] vcpu Pointer to vCPU. - * - * @return None - * - * @pre vcpu != NULL - */ -void vcpu_inject_nmi(struct acrn_vcpu *vcpu); - -/** - * @brief Inject general protection exeception(GP) to guest. - * - * @param[in] vcpu Pointer to vCPU. - * @param[in] err_code Error Code to be injected. - * - * @return None - * - * @pre vcpu != NULL - */ -void vcpu_inject_gp(struct acrn_vcpu *vcpu, uint32_t err_code); - -/** - * @brief Inject page fault exeception(PF) to guest. - * - * @param[in] vcpu Pointer to vCPU. - * @param[in] addr Address that result in PF. - * @param[in] err_code Error Code to be injected. - * - * @return None - * - * @pre vcpu != NULL - */ -void vcpu_inject_pf(struct acrn_vcpu *vcpu, uint64_t addr, uint32_t err_code); - -/** - * @brief Inject invalid opcode exeception(UD) to guest. - * - * @param[in] vcpu Pointer to vCPU. - * - * @return None - * - * @pre vcpu != NULL - */ -void vcpu_inject_ud(struct acrn_vcpu *vcpu); - -/** - * @brief Inject stack fault exeception(SS) to guest. - * - * @param[in] vcpu Pointer to vCPU. - * - * @return None - * - * @pre vcpu != NULL - */ -void vcpu_inject_ss(struct acrn_vcpu *vcpu); -void vcpu_make_request(struct acrn_vcpu *vcpu, uint16_t eventid); - -/* - * @pre vcpu != NULL - */ -int32_t exception_vmexit_handler(struct acrn_vcpu *vcpu); -int32_t nmi_window_vmexit_handler(struct acrn_vcpu *vcpu); -int32_t interrupt_window_vmexit_handler(struct acrn_vcpu *vcpu); -int32_t external_interrupt_vmexit_handler(struct acrn_vcpu *vcpu); -int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu); - -extern uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE]; - -typedef void (*irq_action_t)(uint32_t irq, void *priv_data); - -/** - * @brief Interrupt descriptor - * - * Any field change in below required lock protection with irqsave - */ -struct irq_desc { - uint32_t irq; /**< index to irq_desc_base */ +struct x86_irq_data { uint32_t vector; /**< assigned vector */ - - irq_action_t action; /**< callback registered from component */ - void *priv_data; /**< irq_action private data */ - uint32_t flags; /**< flags for trigger mode/ptdev */ - - spinlock_t lock; #ifdef PROFILING_ON uint64_t ctx_rip; uint64_t ctx_rflags; @@ -276,26 +83,21 @@ struct irq_desc { * @{ */ +uint32_t alloc_irq_vector(uint32_t irq); + /** - * @brief Request an interrupt - * - * Request interrupt num if not specified, and register irq action for the - * specified/allocated irq. + * @brief Get vector number of an interrupt from irq number * - * @param[in] req_irq irq_num to request, if IRQ_INVALID, a free irq - * number will be allocated - * @param[in] action_fn Function to be called when the IRQ occurs - * @param[in] priv_data Private data for action function. - * @param[in] flags Interrupt type flags, including: - * IRQF_NONE; - * IRQF_LEVEL - 1: level trigger; 0: edge trigger; - * IRQF_PT - 1: for passthrough dev + * @param[in] irq The irq_num to convert * - * @retval >=0 on success - * @retval IRQ_INVALID on failure + * @return vector number + */ +uint32_t irq_to_vector(uint32_t irq); + +/** + * @brief Request an interrupt */ -int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, - uint32_t flags); +bool request_irq_arch(uint32_t irq); /** * @brief Free an interrupt @@ -304,26 +106,13 @@ int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, * * @param[in] irq irq_num to be freed */ -void free_irq(uint32_t irq); +void free_irq_arch(uint32_t irq); -/** - * @brief Set interrupt trigger mode - * - * Set the irq trigger mode: edge-triggered or level-triggered - * - * @param[in] irq irq_num of interrupt to be set - * @param[in] is_level_triggered Trigger mode to set - */ -void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered); +void pre_irq_arch(const struct irq_desc *desc); -/** - * @brief Get vector number of an interrupt from irq number - * - * @param[in] irq The irq_num to convert - * - * @return vector number - */ -uint32_t irq_to_vector(uint32_t irq); +void eoi_irq_arch(const struct irq_desc *desc); + +void post_irq_arch(const struct irq_desc *desc); /** * @brief Dispatch interrupt @@ -334,14 +123,8 @@ uint32_t irq_to_vector(uint32_t irq); */ void dispatch_interrupt(const struct intr_excp_ctx *ctx); -/** - * @brief Handle NMI - * - * To handle an NMI - * - * @param ctx Pointer to interrupt exception context - */ -void handle_nmi(__unused struct intr_excp_ctx *ctx); +bool irq_allocated_arch(struct irq_desc *desc); +void init_irq_descs_arch(struct irq_desc descs[]); /** * @brief Initialize interrupt @@ -350,7 +133,9 @@ void handle_nmi(__unused struct intr_excp_ctx *ctx); * * @param[in] pcpu_id The id of physical cpu to initialize */ -void init_interrupt(uint16_t pcpu_id); +void init_interrupt_arch(uint16_t pcpu_id); + +void setup_irqs_arch(void); /** * @} @@ -360,5 +145,5 @@ void init_interrupt(uint16_t pcpu_id); /** * @} */ -/* End of acrn_virq */ +/* End of acrn_x86_irq */ #endif /* ARCH_IRQ_H */ diff --git a/hypervisor/include/arch/x86/lapic.h b/hypervisor/include/arch/x86/lapic.h index 5d4ed845af..fd62e294b3 100644 --- a/hypervisor/include/arch/x86/lapic.h +++ b/hypervisor/include/arch/x86/lapic.h @@ -7,41 +7,6 @@ #ifndef INTR_LAPIC_H #define INTR_LAPIC_H -#include -#include - -/* intr_lapic_icr_delivery_mode */ -#define INTR_LAPIC_ICR_FIXED 0x0U -#define INTR_LAPIC_ICR_LP 0x1U -#define INTR_LAPIC_ICR_SMI 0x2U -#define INTR_LAPIC_ICR_NMI 0x4U -#define INTR_LAPIC_ICR_INIT 0x5U -#define INTR_LAPIC_ICR_STARTUP 0x6U - -/* intr_lapic_icr_dest_mode */ -#define INTR_LAPIC_ICR_PHYSICAL 0x0U -#define INTR_LAPIC_ICR_LOGICAL 0x1U - -/* intr_lapic_icr_level */ -#define INTR_LAPIC_ICR_DEASSERT 0x0U -#define INTR_LAPIC_ICR_ASSERT 0x1U - -/* intr_lapic_icr_trigger */ -#define INTR_LAPIC_ICR_EDGE 0x0U -#define INTR_LAPIC_ICR_LEVEL 0x1U - -/* intr_lapic_icr_shorthand */ -#define INTR_LAPIC_ICR_USE_DEST_ARRAY 0x0U -#define INTR_LAPIC_ICR_SELF 0x1U -#define INTR_LAPIC_ICR_ALL_INC_SELF 0x2U -#define INTR_LAPIC_ICR_ALL_EX_SELF 0x3U - -enum intr_cpu_startup_shorthand { - INTR_CPU_STARTUP_USE_DEST, - INTR_CPU_STARTUP_ALL_EX_SELF, - INTR_CPU_STARTUP_UNKNOWN, -}; - /* x2APIC Interrupt Command Register (ICR) structure */ union apic_icr { uint64_t value; @@ -71,14 +36,6 @@ union apic_icr { * @{ */ -/** - * @brief Save context of LAPIC - * - * @param[inout] regs Pointer to struct lapic_regs to hold the - * context of current LAPIC - */ -void save_lapic(struct lapic_regs *regs); - /** * @brief Enable LAPIC in x2APIC mode * diff --git a/hypervisor/include/arch/x86/lib/bits.h b/hypervisor/include/arch/x86/lib/bits.h index addf22bad9..0928a374ab 100644 --- a/hypervisor/include/arch/x86/lib/bits.h +++ b/hypervisor/include/arch/x86/lib/bits.h @@ -29,7 +29,7 @@ #ifndef BITS_H #define BITS_H -#include +#include /** * diff --git a/hypervisor/include/arch/x86/mmu.h b/hypervisor/include/arch/x86/mmu.h index f123a3c9f3..a984fa4a4b 100644 --- a/hypervisor/include/arch/x86/mmu.h +++ b/hypervisor/include/arch/x86/mmu.h @@ -44,16 +44,16 @@ #ifndef ASSEMBLER -#include -#include -#include -#include +#include +#include +#include +#include /* Define cache line size (in bytes) */ #define CACHE_LINE_SIZE 64U /* IA32E Paging constants */ -#define IA32E_REF_MASK ((get_pcpu_info())->physical_address_mask) +#define IA32E_REF_MASK (((1UL << pcpu_physaddr_bits()) - 1UL) & PAGE_MASK) struct acrn_vcpu; static inline uint64_t round_page_up(uint64_t addr) diff --git a/hypervisor/include/arch/x86/notify.h b/hypervisor/include/arch/x86/notify.h new file mode 100644 index 0000000000..0aede50e1f --- /dev/null +++ b/hypervisor/include/arch/x86/notify.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef NOTIFY_H +#define NOTIFY_H + +typedef void (*smp_call_func_t)(void *data); +struct smp_call_info_data { + smp_call_func_t func; + void *data; +}; + +struct acrn_vm; +void smp_call_function(uint64_t mask, smp_call_func_t func, void *data); +bool is_notification_nmi(const struct acrn_vm *vm); + +void setup_notification(void); +void setup_pi_notification(void); + +#endif diff --git a/hypervisor/include/arch/x86/pci_dev.h b/hypervisor/include/arch/x86/pci_dev.h index 51e1bae9d6..2ef9e79a44 100644 --- a/hypervisor/include/arch/x86/pci_dev.h +++ b/hypervisor/include/arch/x86/pci_dev.h @@ -7,7 +7,7 @@ #ifndef PCI_DEV_H_ #define PCI_DEV_H_ -#include +#include extern struct acrn_vm_pci_dev_config sos_pci_devs[CONFIG_MAX_PCI_DEV_NUM]; diff --git a/hypervisor/include/arch/x86/per_cpu.h b/hypervisor/include/arch/x86/per_cpu.h index e584a37fe7..661632ca19 100644 --- a/hypervisor/include/arch/x86/per_cpu.h +++ b/hypervisor/include/arch/x86/per_cpu.h @@ -9,15 +9,20 @@ #include #include +#include +#include +#include #include -#include +#include +#include +#include #include #include #include -#include +#include #include -#include -#include +#include +#include struct per_cpu_region { /* vmxon_region MUST be 4KB-aligned */ diff --git a/hypervisor/include/arch/x86/pgtable.h b/hypervisor/include/arch/x86/pgtable.h index 7f19a79a4e..dc5c861bfc 100644 --- a/hypervisor/include/arch/x86/pgtable.h +++ b/hypervisor/include/arch/x86/pgtable.h @@ -11,7 +11,7 @@ #ifndef PGTABLE_H #define PGTABLE_H -#include +#include #define PAGE_PRESENT (1UL << 0U) #define PAGE_RW (1UL << 1U) diff --git a/hypervisor/include/arch/x86/ptintr.h b/hypervisor/include/arch/x86/ptintr.h new file mode 100644 index 0000000000..927c64c9ff --- /dev/null +++ b/hypervisor/include/arch/x86/ptintr.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ARCH_PTINTR_H +#define ARCH_PTINTR_H + +#include + +int32_t ptintr_add_intx_arch(struct acrn_vm *vm, union source_id *virt_sid); +int32_t ptintr_remap_msix_arch(struct ptintr *intr, struct ptintr_remap_msix *args); +int32_t ptintr_remap_intx_arch(struct ptintr *intr, struct ptintr_remap_intx *args); +void ptintr_remove_msix_arch(struct ptintr *intr); +void ptintr_remove_intx_arch(struct ptintr *intr); +void ptintr_init_arch(struct ptintr *(*find)(uint32_t, const union source_id *, + const struct acrn_vm *)); +#endif /* ARCH_PTINTR_H */ diff --git a/hypervisor/include/arch/x86/ptirq.h b/hypervisor/include/arch/x86/ptirq.h new file mode 100644 index 0000000000..eb2144b2cd --- /dev/null +++ b/hypervisor/include/arch/x86/ptirq.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ARCH_PTIRQ_H +#define ARCH_PTIRQ_H + +#include + +void ptirq_softirq_arch(struct ptirq *irq); +uint32_t ptirq_get_irq_arch(uint32_t intr_type, union source_id *phys_sid); +void ptirq_intx_ack_arch(struct ptirq *irq); +#endif /* ARCH_PTIRQ_H */ diff --git a/hypervisor/include/arch/x86/rtcm.h b/hypervisor/include/arch/x86/rtcm.h index 95959c6b81..5736f342ac 100644 --- a/hypervisor/include/arch/x86/rtcm.h +++ b/hypervisor/include/arch/x86/rtcm.h @@ -7,7 +7,7 @@ #ifndef RTCM_H #define RTCM_H -#include +#include #define MSABI __attribute__((ms_abi)) diff --git a/hypervisor/include/arch/x86/seed.h b/hypervisor/include/arch/x86/seed.h index bd35a52cf6..ea6e4ab09d 100644 --- a/hypervisor/include/arch/x86/seed.h +++ b/hypervisor/include/arch/x86/seed.h @@ -19,13 +19,6 @@ struct seed_info { uint8_t seed[BUP_MKHI_BOOTLOADER_SEED_LEN]; }; -/* Structure of physical seed */ -struct physical_seed { - struct seed_info seed_list[BOOTLOADER_SEED_MAX_ENTRIES]; - uint32_t num_seeds; - uint32_t pad; -}; - void init_seed(void); void fill_seed_arg(char *cmd_dst, size_t cmd_sz); diff --git a/hypervisor/include/arch/x86/tsc.h b/hypervisor/include/arch/x86/tsc.h new file mode 100644 index 0000000000..4ead766725 --- /dev/null +++ b/hypervisor/include/arch/x86/tsc.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TSC_H +#define TSC_H + +/** + * @brief Calibrate tsc. + * + * @return None + */ +void calibrate_tsc(void); + +#endif diff --git a/hypervisor/include/arch/x86/vm_config.h b/hypervisor/include/arch/x86/vm_config.h index 7a32925648..7251310e55 100644 --- a/hypervisor/include/arch/x86/vm_config.h +++ b/hypervisor/include/arch/x86/vm_config.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #define CONFIG_MAX_VM_NUM (PRE_VM_NUM + SOS_VM_NUM + MAX_POST_VM_NUM) diff --git a/hypervisor/include/arch/x86/zeropage.h b/hypervisor/include/arch/x86/zeropage.h index 746ce29ef4..249949f1ed 100644 --- a/hypervisor/include/arch/x86/zeropage.h +++ b/hypervisor/include/arch/x86/zeropage.h @@ -6,7 +6,8 @@ #ifndef ZEROPAGE_H #define ZEROPAGE_H -#include + +#include #include struct zero_page { diff --git a/hypervisor/include/common/cycles.h b/hypervisor/include/common/cycles.h new file mode 100644 index 0000000000..0e31b4c567 --- /dev/null +++ b/hypervisor/include/common/cycles.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CYCLES_H +#define CYCLES_H + +#include + +#define CYCLES_PER_MS us_to_cycles(1000U) + +/** + * @brief Get cpu frequency. + * + * @return frequency(KHz) + */ +uint32_t get_cpu_freq(void); + +/** + * @brief Get cpu cycles. + * + * @return cycles + */ +uint64_t get_cpu_cycles(void); + +/** + * @brief convert us to cycles. + * + * @return cycles + */ +uint64_t us_to_cycles(uint32_t us); + +/** + * @brief convert cycles to us. + * + * @return microsecond + */ +uint64_t cycles_to_us(uint64_t ticks); + +/** + * @brief convert cycles to ms. + * + * @return millisecond + */ +uint64_t cycles_to_ms(uint64_t ticks); +#endif diff --git a/hypervisor/include/common/event.h b/hypervisor/include/common/event.h index c7f3980328..77b625ff79 100644 --- a/hypervisor/include/common/event.h +++ b/hypervisor/include/common/event.h @@ -1,6 +1,6 @@ #ifndef EVENT_H #define EVENT_H -#include +#include struct sched_event { spinlock_t lock; diff --git a/hypervisor/include/common/irq.h b/hypervisor/include/common/irq.h new file mode 100644 index 0000000000..3b3ddfb89f --- /dev/null +++ b/hypervisor/include/common/irq.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef IRQ_H +#define IRQ_H + +/** + * @file common/irq.h + * + * @brief public APIs for virtual IRQ + */ + +#define NR_IRQS 256U +#define IRQ_INVALID 0xffffffffU + +#define IRQ_ALLOC_BITMAP_SIZE INT_DIV_ROUNDUP(NR_IRQS, 64U) + +#define IRQF_NONE (0U) +#define IRQF_LEVEL (1U << 1U) /* 1: level trigger; 0: edge trigger */ +#define IRQF_PT (1U << 2U) /* 1: for passthrough dev */ + +/** + * @brief virtual IRQ + * + * @addtogroup acrn_virq ACRN vIRQ + * @{ + */ + +extern uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE]; + +typedef void (*irq_action_t)(uint32_t irq, void *priv_data); + +/** + * @brief Interrupt descriptor + * + * Any field change in below required lock protection with irqsave + */ +struct irq_desc { + uint32_t irq; /**< index to irq_desc_base */ + void *arch_data; /**< arch-specific data */ + + irq_action_t action; /**< callback registered from component */ + void *priv_data; /**< irq_action private data */ + uint32_t flags; /**< flags for trigger mode/ptdev */ + + spinlock_t lock; +}; + +/** + * @defgroup phys_int_ext_apis Physical Interrupt External Interfaces + * + * This is a group that includes Physical Interrupt External Interfaces. + * + * @{ + */ + +uint32_t reserve_irq_num(uint32_t req_irq); + +/** + * @brief Request an interrupt + * + * Request interrupt num if not specified, and register irq action for the + * specified/allocated irq. + * + * @param[in] req_irq irq_num to request, if IRQ_INVALID, a free irq + * number will be allocated + * @param[in] action_fn Function to be called when the IRQ occurs + * @param[in] priv_data Private data for action function. + * @param[in] flags Interrupt type flags, including: + * IRQF_NONE; + * IRQF_LEVEL - 1: level trigger; 0: edge trigger; + * IRQF_PT - 1: for passthrough dev + * + * @retval >=0 on success + * @retval IRQ_INVALID on failure + */ +int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, + uint32_t flags); + +/** + * @brief Free an interrupt + * + * Free irq num and unregister the irq action. + * + * @param[in] irq irq_num to be freed + */ +void free_irq(uint32_t irq); + +/** + * @brief Set interrupt trigger mode + * + * Set the irq trigger mode: edge-triggered or level-triggered + * + * @param[in] irq irq_num of interrupt to be set + * @param[in] is_level_triggered Trigger mode to set + */ +void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered); + +/** + * @brief Process an IRQ + * + * To process an IRQ, an action callback will be called if registered. + * + * @param irq irq_num to be processed + */ +void do_irq(const uint32_t irq); + +/** + * @brief Initialize interrupt + * + * To do interrupt initialization for a cpu, will be called for each physical cpu. + * + * @param[in] pcpu_id The id of physical cpu to initialize + */ +void init_interrupt(uint16_t pcpu_id); + +/** + * @} + */ +/* End of phys_int_ext_apis */ + +/** + * @} + */ +/* End of acrn_virq */ +#endif /* IRQ_H */ diff --git a/hypervisor/include/common/ptdev.h b/hypervisor/include/common/ptdev.h deleted file mode 100644 index 6a006d4e78..0000000000 --- a/hypervisor/include/common/ptdev.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef PTDEV_H -#define PTDEV_H -#include -#include -#include - - -enum intx_ctlr { - INTX_CTLR_IOAPIC = 0U, - INTX_CTLR_PIC -}; - -#define PTDEV_INTR_MSI (1U << 0U) -#define PTDEV_INTR_INTX (1U << 1U) - -#define INVALID_PTDEV_ENTRY_ID 0xffffU - -#define DEFINE_MSI_SID(name, a, b) \ -union source_id (name) = {.msi_id = {.bdf = (a), .entry_nr = (b)} } - -#define DEFINE_INTX_SID(name, a, b) \ -union source_id (name) = {.intx_id = {.gsi = (a), .ctlr = (b)} } - -union irte_index { - uint16_t index; - struct { - uint16_t index_low:15; - uint16_t index_high:1; - } bits __packed; -}; - - -union source_id { - uint64_t value; - struct { - uint16_t bdf; - uint16_t entry_nr; - uint32_t reserved; - } msi_id; - /* - * ctlr indicates if the source of interrupt is IO-APIC or PIC - * pin indicates the pin number of interrupt controller determined by ctlr - */ - struct { - enum intx_ctlr ctlr; - uint32_t gsi; - } intx_id; -}; - -/* - * Macros for bits in union msi_addr_reg - */ - -#define MSI_ADDR_BASE 0xfeeUL /* Base address for MSI messages */ -#define MSI_ADDR_RH 0x1U /* Redirection Hint */ -#define MSI_ADDR_DESTMODE_LOGICAL 0x1U /* Destination Mode: Logical*/ -#define MSI_ADDR_DESTMODE_PHYS 0x0U /* Destination Mode: Physical*/ - -union msi_addr_reg { - uint64_t full; - struct { - uint32_t rsvd_1:2; - uint32_t dest_mode:1; - uint32_t rh:1; - uint32_t rsvd_2:8; - uint32_t dest_field:8; - uint32_t addr_base:12; - uint32_t hi_32; - } bits __packed; - struct { - uint32_t rsvd_1:2; - uint32_t intr_index_high:1; - uint32_t shv:1; - uint32_t intr_format:1; - uint32_t intr_index_low:15; - uint32_t constant:12; - uint32_t hi_32; - } ir_bits __packed; - -}; - -/* - * Macros for bits in union msi_data_reg - */ - -#define MSI_DATA_DELMODE_FIXED 0x0U /* Delivery Mode: Fixed */ -#define MSI_DATA_DELMODE_LOPRI 0x1U /* Delivery Mode: Low Priority */ -#define MSI_DATA_TRGRMODE_EDGE 0x0U /* Trigger Mode: Edge */ -#define MSI_DATA_TRGRMODE_LEVEL 0x1U /* Trigger Mode: Level */ - -union msi_data_reg { - uint32_t full; - struct { - uint32_t vector:8; - uint32_t delivery_mode:3; - uint32_t rsvd_1:3; - uint32_t level:1; - uint32_t trigger_mode:1; - uint32_t rsvd_2:16; - } bits __packed; -}; - -struct msi_info { - union msi_addr_reg addr; - union msi_data_reg data; -}; - -struct ptirq_remapping_info; -typedef void (*ptirq_arch_release_fn_t)(const struct ptirq_remapping_info *entry); - -/* entry per each allocated irq/vector - * it represents a pass-thru device's remapping data entry which collecting - * information related with its vm and msi/intx mapping & interaction nodes - * with interrupt handler and softirq. - */ -struct ptirq_remapping_info { - struct hlist_node phys_link; - struct hlist_node virt_link; - uint16_t ptdev_entry_id; - uint32_t intr_type; - union source_id phys_sid; - union source_id virt_sid; - struct acrn_vm *vm; - bool active; /* true=active, false=inactive*/ - uint32_t allocated_pirq; - uint32_t polarity; /* 0=active high, 1=active low*/ - struct list_head softirq_node; - struct msi_info vmsi; - struct msi_info pmsi; - uint16_t irte_idx; - - uint64_t intr_count; - struct hv_timer intr_delay_timer; /* used for delay intr injection */ - ptirq_arch_release_fn_t release_cb; -}; - -static inline bool is_entry_active(const struct ptirq_remapping_info *entry) -{ - return entry->active; -} - -extern struct ptirq_remapping_info ptirq_entries[CONFIG_MAX_PT_IRQ_ENTRIES]; -extern spinlock_t ptdev_lock; - -/** - * @file ptdev.h - * - * @brief public APIs for ptdev - */ - -/** - * @brief ptdev - * - * @addtogroup acrn_passthrough - * @{ - */ - - -/* - * @brief Find a ptdev entry by sid - * - * param[in] intr_type interrupt type of the ptirq entry - * param[in] sid source id of the ptirq entry - * param[in] vm vm pointer of the ptirq entry if find the ptdev entry by virtual sid - * - * @retval NULL when no ptirq entry match the sid - * @retval ptirq entry when there is available ptirq entry match the sid - * - * @pre: vm must be NULL when lookup by physical sid, otherwise, - * vm must not be NULL when lookup by virtual sid. - */ -struct ptirq_remapping_info *find_ptirq_entry(uint32_t intr_type, - const union source_id *sid, const struct acrn_vm *vm); - -/** - * @brief Handler of softirq for passthrough device. - * - * When hypervisor receive a physical interrupt from passthrough device, it - * will enqueue a ptirq entry and raise softirq SOFTIRQ_PTDEV. This function - * is the handler of the softirq, it handles the interrupt and injects the - * virtual into VM. - * The handler is registered by calling @ref ptdev_init during hypervisor - * initialization. - * - * @param[in] pcpu_id physical cpu id of the soft irq - * - */ -void ptirq_softirq(uint16_t pcpu_id); -/** - * @brief Passthrough device global data structure initialization. - * - * During the hypervisor cpu initialization stage, this function: - * - init global spinlock for ptdev (on BSP) - * - register SOFTIRQ_PTDEV handler (on BSP) - * - init the softirq entry list for each CPU - * - */ -void ptdev_init(void); -/** - * @brief Deactivate and release all ptirq entries for a VM. - * - * This function deactivates and releases all ptirq entries for a VM. The function - * should only be called after the VM is already down. - * - * @param[in] vm acrn_vm on which the ptirq entries will be released - * - * @pre VM is already down - * - */ -void ptdev_release_all_entries(const struct acrn_vm *vm); - -/** - * @brief Dequeue an entry from per cpu ptdev softirq queue. - * - * Dequeue an entry from the ptdev softirq queue on the specific physical cpu. - * - * @param[in] pcpu_id physical cpu id - * - * @retval NULL when the queue is empty - * @retval !NULL when there is available ptirq_remapping_info entry in the queue - * - */ -struct ptirq_remapping_info *ptirq_dequeue_softirq(uint16_t pcpu_id); -/** - * @brief Allocate a ptirq_remapping_info entry. - * - * Allocate a ptirq_remapping_info entry for hypervisor to store the remapping information. - * The total number of the entries is statically defined as CONFIG_MAX_PT_IRQ_ENTRIES. - * Appropriate number should be configured on different platforms. - * - * @param[in] vm acrn_vm that the entry allocated for. - * @param[in] intr_type interrupt type: PTDEV_INTR_MSI or PTDEV_INTR_INTX - * - * @retval NULL when the number of entries allocated is CONFIG_MAX_PT_IRQ_ENTRIES - * @retval !NULL when the number of entries allocated is less than CONFIG_MAX_PT_IRQ_ENTRIES - * - */ -struct ptirq_remapping_info *ptirq_alloc_entry(struct acrn_vm *vm, uint32_t intr_type); -/** - * @brief Release a ptirq_remapping_info entry. - * - * @param[in] entry the ptirq_remapping_info entry to release. - * - */ -void ptirq_release_entry(struct ptirq_remapping_info *entry); -/** - * @brief Activate a irq for the associated passthrough device. - * - * After activating the ptirq entry, the physical interrupt irq of passthrough device will be handled - * by the handler ptirq_interrupt_handler. - * - * @param[in] entry the ptirq_remapping_info entry that will be associated with the physical irq. - * @param[in] phys_irq physical interrupt irq for the entry - * - * @retval success when return value >=0 - * @retval failure when return value < 0 - * - */ -int32_t ptirq_activate_entry(struct ptirq_remapping_info *entry, uint32_t phys_irq); -/** - * @brief De-activate a irq for the associated passthrough device. - * - * @param[in] entry the ptirq_remapping_info entry that will be de-activated. - * - */ -void ptirq_deactivate_entry(struct ptirq_remapping_info *entry); -/** - * @brief Get the interrupt information and store to the buffer provided. - * - * @param[in] target_vm the VM to get the interrupt information. - * @param[out] buffer where interrupt information is stored. - * @param[in] buffer_cnt the size of the buffer. - * - * @retval the actual size the buffer filled with the interrupt information - * - */ -uint32_t ptirq_get_intr_data(const struct acrn_vm *target_vm, uint64_t *buffer, uint32_t buffer_cnt); - -/** - * @} - */ - -#endif /* PTDEV_H */ diff --git a/hypervisor/include/common/ptintr.h b/hypervisor/include/common/ptintr.h new file mode 100644 index 0000000000..a4272a354a --- /dev/null +++ b/hypervisor/include/common/ptintr.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PTINTR_H +#define PTINTR_H + +#include + +enum intx_ctlr { + INTX_CTLR_IOAPIC = 0U, + INTX_CTLR_PIC, + INTX_CTLR_MAX = UINT32_MAX +} __packed; + +#define PTDEV_INTR_MSI (1U << 0U) +#define PTDEV_INTR_INTX (1U << 1U) + +#define INVALID_PTDEV_ENTRY_ID 0xffffU + +#define DEFINE_MSI_SID(name, a, b) \ +union source_id (name) = {.msi_id = {.bdf = (a), .entry_nr = (b)} } + +#define DEFINE_INTX_SID(name, a, b) \ +union source_id (name) = {.intx_id = {.gsi = (a), .ctlr = (b)} } + +union source_id { + uint64_t value; + struct { + uint16_t bdf; + uint16_t entry_nr; + uint32_t reserved; + } msi_id; + /* + * ctlr indicates if the source of interrupt is IO-APIC or PIC + * pin indicates the pin number of interrupt controller determined by ctlr + */ + struct { + uint32_t ctlr; + uint32_t gsi; + } intx_id; +}; + +/* + * Macros for bits in union msi_addr_reg + */ +#define MSI_ADDR_BASE 0xfeeUL /* Base address for MSI messages */ +#define MSI_ADDR_RH 0x1U /* Redirection Hint */ +#define MSI_ADDR_DESTMODE_LOGICAL 0x1U /* Destination Mode: Logical*/ +#define MSI_ADDR_DESTMODE_PHYS 0x0U /* Destination Mode: Physical*/ + +union msi_addr_reg { + uint64_t full; + struct { + uint32_t rsvd_1:2; + uint32_t dest_mode:1; + uint32_t rh:1; + uint32_t rsvd_2:8; + uint32_t dest_field:8; + uint32_t addr_base:12; + uint32_t hi_32; + } bits __packed; + struct { + uint32_t rsvd_1:2; + uint32_t intr_index_high:1; + uint32_t shv:1; + uint32_t intr_format:1; + uint32_t intr_index_low:15; + uint32_t constant:12; + uint32_t hi_32; + } ir_bits __packed; + +}; + +/* + * Macros for bits in union msi_data_reg + */ +#define MSI_DATA_DELMODE_FIXED 0x0U /* Delivery Mode: Fixed */ +#define MSI_DATA_DELMODE_LOPRI 0x1U /* Delivery Mode: Low Priority */ +#define MSI_DATA_TRGRMODE_EDGE 0x0U /* Trigger Mode: Edge */ +#define MSI_DATA_TRGRMODE_LEVEL 0x1U /* Trigger Mode: Level */ + +union msi_data_reg { + uint32_t full; + struct { + uint32_t vector:8; + uint32_t delivery_mode:3; + uint32_t rsvd_1:3; + uint32_t level:1; + uint32_t trigger_mode:1; + uint32_t rsvd_2:16; + } bits __packed; +}; + +struct msi_info { + union msi_addr_reg addr; + union msi_data_reg data; +}; + +struct ptintr_add_args { + uint32_t intr_type; + union { + struct ptintr_add_msix { + uint16_t virt_bdf; + uint16_t phys_bdf; + uint16_t entry_nr; + } msix; + struct ptintr_add_intx { + uint32_t virt_gsi; + uint32_t virt_ctlr; + uint32_t phys_gsi; + uint32_t phys_ctlr; + } intx; + }; +}; + +struct ptintr_remap_args { + uint32_t intr_type; + union { + struct ptintr_remap_msix { + uint16_t virt_bdf; + uint16_t entry_nr; + uint16_t irte_idx; + struct msi_info *info; + void *remap_arg; + int32_t (*remap_cb)(void *); + } msix; + struct ptintr_remap_intx { + uint32_t virt_gsi; + uint32_t virt_ctlr; + } intx; + }; +}; + +struct ptintr_rmv_args { + uint32_t intr_type; + union { + struct ptintr_rmv_msix { + uint16_t phys_bdf; + uint32_t entry_nr; + } msix; + struct ptintr_rmv_intx { + uint32_t virt_gsi; + uint32_t virt_ctlr; + } intx; + }; +}; + +struct ptirq; + +/* + * one entry per allocated irq/vector + * it represents a pass-thru device's remapping data entry which collecting + * information related with its vm and msi/intx mapping & interaction nodes + * with interrupt handler and softirq. + */ +struct ptintr { + struct hlist_node phys_link; + struct hlist_node virt_link; + uint16_t id; + uint32_t intr_type; + bool active; /* true=active, false=inactive */ + union source_id phys_sid; + union source_id virt_sid; + struct acrn_vm *vm; + struct msi_info pmsi; + uint16_t irte_idx; + struct ptirq *irq; +}; + +extern struct ptintr ptintr_entries[CONFIG_MAX_PT_IRQ_ENTRIES]; + +int32_t ptintr_add(struct acrn_vm *vm, struct ptintr_add_args *args); +int32_t ptintr_remap(struct acrn_vm *vm, struct ptintr_remap_args *args); +void ptintr_remove_and_unmap(struct acrn_vm *vm, struct ptintr_rmv_args *args); +void ptintr_remove_and_unmap_vm(const struct acrn_vm *vm); +void ptintr_intx_ack(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_ctlr); +uint32_t ptintr_get_intr_data(const struct acrn_vm *target_vm, uint64_t *buffer, uint32_t buffer_cnt); +void ptintr_init(void); +#endif /* PTINTR_H */ diff --git a/hypervisor/include/common/ptirq.h b/hypervisor/include/common/ptirq.h new file mode 100644 index 0000000000..e6cd8c8e97 --- /dev/null +++ b/hypervisor/include/common/ptirq.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PTIRQ_H +#define PTIRQ_H + +#include +#include + +struct ptirq { + uint16_t id; + struct acrn_vm *vm; + uint32_t intr_type; + union source_id virt_sid; + bool active; /* true=active, false=inactive */ + uint32_t allocated_pirq; + struct list_head softirq_node; + uint32_t polarity; /* 0=active high, 1=active low */ + struct msi_info vmsi; + uint64_t intr_count; + struct hv_timer intr_delay_timer; /* used for delayed intr injection */ +}; + +void ptirq_set_vmsi(struct ptirq *irq, struct msi_info *vmsi); +void ptirq_set_polarity(struct ptirq *irq, uint32_t polarity); +uint32_t ptirq_get_polarity(struct ptirq *irq); +uint32_t ptirq_get_irq(struct ptirq *irq); +int32_t ptirq_request(struct ptirq **irq, struct acrn_vm *vm, uint32_t intr_type, + union source_id *phys_sid, union source_id *virt_sid); +void ptirq_free(struct ptirq *irq); +int32_t ptirq_get_intr_data(struct ptirq *irq, uint64_t *buffer, + uint32_t *pos, uint32_t buffer_cnt); +void ptirq_init(void); +#endif /* PTIRQ_H */ diff --git a/hypervisor/include/common/schedule.h b/hypervisor/include/common/schedule.h index 8400c75abf..09e5f8b9a0 100644 --- a/hypervisor/include/common/schedule.h +++ b/hypervisor/include/common/schedule.h @@ -6,7 +6,7 @@ #ifndef SCHEDULE_H #define SCHEDULE_H -#include +#include #include #include diff --git a/hypervisor/include/arch/x86/timer.h b/hypervisor/include/common/timer.h similarity index 62% rename from hypervisor/include/arch/x86/timer.h rename to hypervisor/include/common/timer.h index 71c5af6acc..315e607298 100644 --- a/hypervisor/include/arch/x86/timer.h +++ b/hypervisor/include/common/timer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Intel Corporation. All rights reserved. + * Copyright (C) 2020 Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -8,6 +8,7 @@ #define TIMER_H #include +#include /** * @brief Timer @@ -39,54 +40,19 @@ struct per_cpu_timers { struct hv_timer { struct list_head node; /**< link all timers */ enum tick_mode mode; /**< timer mode: one-shot or periodic */ - uint64_t fire_tsc; /**< tsc deadline to interrupt */ + uint64_t timeout; /**< tsc deadline to interrupt */ uint64_t period_in_cycle; /**< period of the periodic timer in unit of TSC cycles */ timer_handle_t func; /**< callback if time reached */ void *priv_data; /**< func private data */ }; -/* External Interfaces */ - -#define CYCLES_PER_MS us_to_ticks(1000U) - -void udelay(uint32_t us); - -/** - * @brief convert us to ticks. - * - * @return ticks - */ -uint64_t us_to_ticks(uint32_t us); - -/** - * @brief convert ticks to us. - * - * @return microsecond - */ -uint64_t ticks_to_us(uint64_t ticks); - -/** - * @brief convert ticks to ms. - * - * @return millisecond - */ -uint64_t ticks_to_ms(uint64_t ticks); - -/** - * @brief read tsc. - * - * @return tsc value - */ -uint64_t rdtsc(void); - /** * @brief Initialize a timer structure. * * @param[in] timer Pointer to timer. * @param[in] func irq callback if time reached. * @param[in] priv_data func private data. - * @param[in] fire_tsc tsc deadline to interrupt. - * @param[in] mode timer mode. + * @param[in] timeout deadline to interrupt. * @param[in] period_in_cycle period of the periodic timer in unit of TSC cycles. * * @remark Don't initialize a timer twice if it has been added to the timer list @@ -94,43 +60,41 @@ uint64_t rdtsc(void); * * @return None */ -static inline void initialize_timer(struct hv_timer *timer, +void initialize_timer(struct hv_timer *timer, timer_handle_t func, void *priv_data, - uint64_t fire_tsc, int32_t mode, uint64_t period_in_cycle) -{ - if (timer != NULL) { - timer->func = func; - timer->priv_data = priv_data; - timer->fire_tsc = fire_tsc; - timer->mode = mode; - timer->period_in_cycle = period_in_cycle; - INIT_LIST_HEAD(&timer->node); - } -} + uint64_t timeout, uint64_t period_in_cycle); /** * @brief Check a timer whether expired. * * @param[in] timer Pointer to timer. + * @param[in] now to compare. + * @param[in] delta Pointer to return the delta (timeout - now) if timer is not expired. * * @retval true if the timer is expired, false otherwise. */ -static inline bool timer_expired(const struct hv_timer *timer) -{ - return ((timer->fire_tsc == 0UL) || (rdtsc() >= timer->fire_tsc)); -} +bool timer_expired(const struct hv_timer *timer, uint64_t now, uint64_t *delta); /** * @brief Check a timer whether in timer list. * * @param[in] timer Pointer to timer. + * @param[in] timeout deadline to interrupt. * * @retval true if the timer is in timer list, false otherwise. */ -static inline bool timer_is_started(const struct hv_timer *timer) -{ - return (!list_empty(&timer->node)); -} +bool timer_is_started(const struct hv_timer *timer); + +/** + * @brief Update a timer. + * + * @param[in] timer Pointer to timer. + * @param[in] timeout deadline to interrupt. + * @param[in] period_in_cycle period of the periodic timer in unit of TSC cycles. + * + * @return None + */ +void update_timer(struct hv_timer *timer, uint64_t timeout, uint64_t period_in_cycle); /** * @brief Add a timer. @@ -162,20 +126,6 @@ void del_timer(struct hv_timer *timer); */ void timer_init(void); -/** - * @brief Calibrate tsc. - * - * @return None - */ -void calibrate_tsc(void); - -/** - * @brief Get tsc. - * - * @return tsc(KHz) - */ -uint32_t get_tsc_khz(void); - /** * @} */ diff --git a/hypervisor/include/common/udelay.h b/hypervisor/include/common/udelay.h new file mode 100644 index 0000000000..d5faab80cd --- /dev/null +++ b/hypervisor/include/common/udelay.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef DELAY_H +#define DELAY_H + +#include + +void udelay(uint32_t us); + +#endif diff --git a/hypervisor/include/debug/logmsg.h b/hypervisor/include/debug/logmsg.h index 58596b5913..b90907b304 100644 --- a/hypervisor/include/debug/logmsg.h +++ b/hypervisor/include/debug/logmsg.h @@ -6,7 +6,7 @@ #ifndef LOGMSG_H #define LOGMSG_H -#include +#include /* Logging severity levels */ #define LOG_FATAL 1U diff --git a/hypervisor/include/debug/profiling_internal.h b/hypervisor/include/debug/profiling_internal.h index 03bd0f929c..d4ce7f21e7 100644 --- a/hypervisor/include/debug/profiling_internal.h +++ b/hypervisor/include/debug/profiling_internal.h @@ -9,8 +9,8 @@ #ifdef PROFILING_ON -#include -#include +#include +#include #define MAX_MSR_LIST_NUM 15U #define MAX_PROFILING_MSR_STORE_NUM 1 diff --git a/hypervisor/include/debug/trace.h b/hypervisor/include/debug/trace.h index 9e717e1bcb..772589f1df 100644 --- a/hypervisor/include/debug/trace.h +++ b/hypervisor/include/debug/trace.h @@ -11,7 +11,8 @@ #ifndef TRACE_H #define TRACE_H -#include +#include +#include /* TIMER EVENT */ #define TRACE_TIMER_ACTION_ADDED 0x1U #define TRACE_TIMER_ACTION_PCKUP 0x2U diff --git a/hypervisor/include/dm/vioapic.h b/hypervisor/include/dm/vioapic.h index c5f1f1d776..11db95aa7f 100644 --- a/hypervisor/include/dm/vioapic.h +++ b/hypervisor/include/dm/vioapic.h @@ -37,8 +37,8 @@ * @brief public APIs for virtual I/O APIC */ -#include -#include +#include +#include #include #define VIOAPIC_BASE 0xFEC00000UL diff --git a/hypervisor/include/dm/vpci.h b/hypervisor/include/dm/vpci.h index 813881a2da..d9b57b5511 100644 --- a/hypervisor/include/dm/vpci.h +++ b/hypervisor/include/dm/vpci.h @@ -30,7 +30,7 @@ #ifndef VPCI_H_ #define VPCI_H_ -#include +#include #include #include diff --git a/hypervisor/include/dm/vpic.h b/hypervisor/include/dm/vpic.h index 54c2478b94..14b676430a 100644 --- a/hypervisor/include/dm/vpic.h +++ b/hypervisor/include/dm/vpic.h @@ -145,6 +145,18 @@ void vpic_init(struct acrn_vm *vm); * @{ */ +/** + * @brief Set vPIC IRQ line status, without acquiring the vPIC lock. + * + * @param[in] vpic Pointer to virtual pic structure + * @param[in] irqline Target IRQ number + * @param[in] operation action options:GSI_SET_HIGH/GSI_SET_LOW/ + * GSI_RAISING_PULSE/GSI_FALLING_PULSE + * + * @return None + */ +void vpic_set_irqline_nolock(struct acrn_vpic *vpic, uint32_t vgsi, uint32_t operation); + /** * @brief Set vPIC IRQ line status. * @@ -155,7 +167,7 @@ void vpic_init(struct acrn_vm *vm); * * @return None */ -void vpic_set_irqline(struct acrn_vpic *vpic, uint32_t vgsi, uint32_t operation); +void vpic_set_irqline_lock(struct acrn_vpic *vpic, uint32_t vgsi, uint32_t operation); /** * @brief Get pending virtual interrupts for vPIC. diff --git a/hypervisor/include/dm/vuart.h b/hypervisor/include/dm/vuart.h index 51db8f5ccf..1c8a01ec36 100644 --- a/hypervisor/include/dm/vuart.h +++ b/hypervisor/include/dm/vuart.h @@ -30,8 +30,8 @@ #ifndef VUART_H #define VUART_H #include -#include -#include +#include +#include #define RX_BUF_SIZE 256U #define TX_BUF_SIZE 8192U diff --git a/hypervisor/include/hw/hw_timer.h b/hypervisor/include/hw/hw_timer.h new file mode 100644 index 0000000000..32633b382a --- /dev/null +++ b/hypervisor/include/hw/hw_timer.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef HW_TIMER_H +#define HW_TIMER_H + +#include + +void set_hw_timeout(uint64_t timeout); +void init_hw_timer(void); + +#endif diff --git a/hypervisor/release/dump.c b/hypervisor/release/dump.c index a367ab66bc..1c042f3fff 100644 --- a/hypervisor/release/dump.c +++ b/hypervisor/release/dump.c @@ -5,7 +5,7 @@ */ #include -#include +#include void dump_intr_excp_frame(__unused const struct intr_excp_ctx *ctx) {} void dump_exception(__unused struct intr_excp_ctx *ctx, __unused uint16_t pcpu_id) {} diff --git a/hypervisor/release/hypercall.c b/hypervisor/release/hypercall.c index b7eb841b66..c1ea9c170b 100644 --- a/hypervisor/release/hypercall.c +++ b/hypervisor/release/hypercall.c @@ -6,7 +6,7 @@ #include #include -#include +#include int32_t hcall_setup_sbuf(__unused struct acrn_vm *vm, __unused struct acrn_vm *target_vm, __unused uint64_t param1, __unused uint64_t param2) diff --git a/hypervisor/release/profiling.c b/hypervisor/release/profiling.c index 0d86a98f31..894e14b642 100644 --- a/hypervisor/release/profiling.c +++ b/hypervisor/release/profiling.c @@ -5,7 +5,7 @@ */ #include -#include +#include void profiling_vmenter_handler(__unused struct acrn_vcpu *vcpu) {} void profiling_pre_vmexit_handler(__unused struct acrn_vcpu *vcpu) {} diff --git a/misc/config_tools/board_config/board_c.py b/misc/config_tools/board_config/board_c.py index 544b358106..9b359f182f 100644 --- a/misc/config_tools/board_config/board_c.py +++ b/misc/config_tools/board_config/board_c.py @@ -15,9 +15,9 @@ class RDT(enum.Enum): MBA = 2 INCLUDE_HEADER = """ -#include -#include -#include +#include +#include +#include #include #include """ diff --git a/misc/config_tools/data/nuc7i7dnb/industry.xml b/misc/config_tools/data/nuc7i7dnb/industry.xml index 3150e2bc5c..b9bfe42276 100644 --- a/misc/config_tools/data/nuc7i7dnb/industry.xml +++ b/misc/config_tools/data/nuc7i7dnb/industry.xml @@ -126,8 +126,8 @@ VUART_LEGACY_PIO - COM1_BASE - COM1_IRQ + COM2_BASE + COM2_IRQ VUART_LEGACY_PIO diff --git a/misc/config_tools/scenario_config/ivshmem_cfg_h.py b/misc/config_tools/scenario_config/ivshmem_cfg_h.py index 5b06448a1d..1aa737e819 100644 --- a/misc/config_tools/scenario_config/ivshmem_cfg_h.py +++ b/misc/config_tools/scenario_config/ivshmem_cfg_h.py @@ -95,7 +95,7 @@ def generate_file(scenario_items, config): if vm_info.shmem.shmem_enabled == 'y': print("#include ", file=config) - print("#include ", file=config) + print("#include ", file=config) write_shmem_regions(config) print("{0}".format(IVSHMEM_END_DEFINE), file=config) diff --git a/misc/config_tools/scenario_config/pci_dev_c.py b/misc/config_tools/scenario_config/pci_dev_c.py index a85910c440..700eb7b3ec 100644 --- a/misc/config_tools/scenario_config/pci_dev_c.py +++ b/misc/config_tools/scenario_config/pci_dev_c.py @@ -123,12 +123,12 @@ def generate_file(vm_info, config): print("{}".format(scenario_cfg_lib.HEADER_LICENSE), file=config) print("", file=config) - print("#include ", file=config) + print("#include ", file=config) print("#include ", file=config) print("#include ", file=config) print("#include ", file=config) - print("#include ", file=config) - print("#include ", file=config) + print("#include ", file=config) + print("#include ", file=config) if pci_vuart_enabled: print("#include ", file=config) # Insert header for share memory diff --git a/misc/config_tools/scenario_config/pt_intx_c.py b/misc/config_tools/scenario_config/pt_intx_c.py index ade30eed50..96ef2a0968 100644 --- a/misc/config_tools/scenario_config/pt_intx_c.py +++ b/misc/config_tools/scenario_config/pt_intx_c.py @@ -17,7 +17,7 @@ def generate_file(vm_info, config): print("{}".format(scenario_cfg_lib.HEADER_LICENSE), file=config) print("", file=config) - print("#include ", file=config) + print("#include ", file=config) print("", file=config) if (board_cfg_lib.is_matched_board(("ehl-crb-b")) diff --git a/misc/config_tools/scenario_config/vm_configurations_c.py b/misc/config_tools/scenario_config/vm_configurations_c.py index 6810325cca..4fa512d24f 100644 --- a/misc/config_tools/scenario_config/vm_configurations_c.py +++ b/misc/config_tools/scenario_config/vm_configurations_c.py @@ -9,9 +9,9 @@ import scenario_cfg_lib C_HEADER = scenario_cfg_lib.HEADER_LICENSE + r""" -#include +#include #include -#include +#include """ def get_pre_vm_type(vm_type, vm_i): diff --git a/misc/hv_prebuild/static_checks.c b/misc/hv_prebuild/static_checks.c index ba23313eb0..077b72ec3f 100644 --- a/misc/hv_prebuild/static_checks.c +++ b/misc/hv_prebuild/static_checks.c @@ -6,9 +6,9 @@ #include #include -#include -#include -#include +#include +#include +#include #define CAT__(A,B) A ## B #define CAT_(A,B) CAT__(A,B) diff --git a/misc/hv_prebuild/vm_cfg_checks.c b/misc/hv_prebuild/vm_cfg_checks.c index 3acf3e0304..1eb26dcdc1 100644 --- a/misc/hv_prebuild/vm_cfg_checks.c +++ b/misc/hv_prebuild/vm_cfg_checks.c @@ -4,10 +4,10 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include