From 5a2b89b0a43931ed19e71e879456ff688cfe5930 Mon Sep 17 00:00:00 2001 From: Liang Yi Date: Thu, 8 Apr 2021 17:36:12 +0800 Subject: [PATCH] hv/mod_timer: split tsc handling code from timer. Generalize and split basic cpu cycle/tick routines from x86/timer: - Instead of rdstc(), use cpu_ticks() in generic code. - Instead of get_tsc_khz(), use cpu_tickrate() in generic code. - Include "common/ticks.h" instead of "x86/timer.h" in generic code. - CYCLES_PER_MS is renamed to TICKS_PER_MS. The x86 specific API rdstc() and get_tsc_khz(), as well as TSC_PER_MS are still available in arch/x86/tsc.h but only for x86 specific usage. Tracked-On: #5920 Signed-off-by: Rong Liu Signed-off-by: Yi Liang --- doc/acrn.doxyfile | 2 + hypervisor/Makefile | 2 + hypervisor/arch/x86/cpu.c | 7 +- hypervisor/arch/x86/guest/hyperv.c | 1 + hypervisor/arch/x86/guest/trusty.c | 3 +- hypervisor/arch/x86/guest/vcpuid.c | 1 + hypervisor/arch/x86/guest/vlapic.c | 5 +- hypervisor/arch/x86/guest/vmsr.c | 1 + hypervisor/arch/x86/timer.c | 135 +----------------------- hypervisor/arch/x86/tsc.c | 124 ++++++++++++++++++++++ hypervisor/arch/x86/vtd.c | 10 +- hypervisor/common/hypercall.c | 3 +- hypervisor/common/ptdev.c | 4 +- hypervisor/common/sched_bvt.c | 11 +- hypervisor/common/sched_iorr.c | 11 +- hypervisor/common/ticks.c | 31 ++++++ hypervisor/debug/console.c | 5 +- hypervisor/debug/logmsg.c | 3 +- hypervisor/debug/profiling.c | 9 +- hypervisor/debug/trace.c | 3 +- hypervisor/include/arch/x86/asm/timer.h | 45 +------- hypervisor/include/arch/x86/asm/tsc.h | 41 +++++++ hypervisor/include/common/ticks.h | 53 ++++++++++ 23 files changed, 301 insertions(+), 209 deletions(-) create mode 100644 hypervisor/arch/x86/tsc.c create mode 100644 hypervisor/common/ticks.c create mode 100644 hypervisor/include/arch/x86/asm/tsc.h create mode 100644 hypervisor/include/common/ticks.h diff --git a/doc/acrn.doxyfile b/doc/acrn.doxyfile index f721a5ea8..98251a6a0 100644 --- a/doc/acrn.doxyfile +++ b/doc/acrn.doxyfile @@ -808,6 +808,7 @@ INPUT = custom-doxygen/mainpage.md \ ../hypervisor/include/arch/x86/asm/guest/assign.h \ ../hypervisor/include/arch/x86/asm/guest/vcpu.h \ ../hypervisor/include/arch/x86/asm/guest/virtual_cr.h \ + ../hypervisor/include/arch/x86/asm/tsc.h \ ../hypervisor/include/arch/x86/asm/timer.h \ ../hypervisor/include/arch/x86/asm/ioapic.h \ ../hypervisor/include/arch/x86/asm/lapic.h \ @@ -817,6 +818,7 @@ INPUT = custom-doxygen/mainpage.md \ ../hypervisor/include/dm/io_req.h \ ../hypervisor/include/common/hypercall.h \ ../hypervisor/include/common/irq.h \ + ../hypervisor/include/common/ticks.h \ ../hypervisor/include/common/ptdev.h \ ../hypervisor/include/public/acrn_common.h \ ../hypervisor/include/public/acrn_hv_defs.h \ diff --git a/hypervisor/Makefile b/hypervisor/Makefile index c31d812c1..7750c0edf 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -219,6 +219,7 @@ HW_C_SRCS += arch/x86/gdt.c HW_C_SRCS += arch/x86/nmi.c HW_C_SRCS += arch/x86/exception.c HW_C_SRCS += arch/x86/irq.c +HW_C_SRCS += arch/x86/tsc.c HW_C_SRCS += arch/x86/timer.c HW_C_SRCS += arch/x86/vmx.c HW_C_SRCS += arch/x86/cpu_state_tbl.c @@ -228,6 +229,7 @@ HW_C_SRCS += arch/x86/trampoline.c 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/ticks.c HW_C_SRCS += common/irq.c HW_C_SRCS += common/softirq.c HW_C_SRCS += common/schedule.c diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index 8cf6e167c..acc20d5ae 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -32,6 +32,7 @@ #include #include #include +#include #define CPU_UP_TIMEOUT 100U /* millisecond */ #define CPU_DOWN_TIMEOUT 100U /* millisecond */ @@ -49,7 +50,7 @@ static void init_keylocker(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"))); +static uint64_t start_tick __attribute__((__section__(".bss_noinit"))); /** * @pre phys_cpu_num <= MAX_PCPU_NUM @@ -124,7 +125,7 @@ void init_pcpu_pre(bool is_bsp) if (is_bsp) { pcpu_id = BSP_CPU_ID; - start_tsc = rdtsc(); + start_tick = cpu_ticks(); /* Get CPU capabilities thru CPUID, including the physical address bit * limit which is required for initializing paging. @@ -220,7 +221,7 @@ void init_pcpu_post(uint16_t pcpu_id) 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)); + HV_BUILD_USER, HV_CONFIG_TOOL, ticks_to_us(start_tick)); pr_acrnlog("API version %u.%u", HV_API_MAJOR_VERSION, HV_API_MINOR_VERSION); diff --git a/hypervisor/arch/x86/guest/hyperv.c b/hypervisor/arch/x86/guest/hyperv.c index 29facbd83..5bd322583 100644 --- a/hypervisor/arch/x86/guest/hyperv.c +++ b/hypervisor/arch/x86/guest/hyperv.c @@ -12,6 +12,7 @@ #include #include #include +#include #define DBG_LEVEL_HYPERV 6U diff --git a/hypervisor/arch/x86/guest/trusty.c b/hypervisor/arch/x86/guest/trusty.c index f31a456d2..160d2de3e 100644 --- a/hypervisor/arch/x86/guest/trusty.c +++ b/hypervisor/arch/x86/guest/trusty.c @@ -17,6 +17,7 @@ #include #include #include +#include #define TRUSTY_VERSION 1U #define TRUSTY_VERSION_2 2U @@ -282,7 +283,7 @@ static bool setup_trusty_info(struct acrn_vcpu *vcpu, uint32_t mem_size, uint64_ /* Prepare trusty startup param */ startup_param.size_of_this_struct = sizeof(struct trusty_startup_param); startup_param.mem_size = mem_size; - startup_param.tsc_per_ms = CYCLES_PER_MS; + startup_param.tsc_per_ms = TSC_PER_MS; startup_param.trusty_mem_base = TRUSTY_EPT_REBASE_GPA; /* According to trusty boot protocol, it will use RDI as the diff --git a/hypervisor/arch/x86/guest/vcpuid.c b/hypervisor/arch/x86/guest/vcpuid.c index a776bccbd..7beeb8dae 100644 --- a/hypervisor/arch/x86/guest/vcpuid.c +++ b/hypervisor/arch/x86/guest/vcpuid.c @@ -13,6 +13,7 @@ #include #include #include +#include #include static inline const struct vcpuid_entry *local_find_vcpuid_entry(const struct acrn_vcpu *vcpu, diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 4d0c4abf7..c4f534727 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "vlapic_priv.h" #define VLAPIC_VERBOS 0 @@ -281,7 +282,7 @@ static void vlapic_reset_timer(struct acrn_vlapic *vlapic) static bool set_expiration(struct acrn_vlapic *vlapic) { - uint64_t now = rdtsc(); + uint64_t now = cpu_ticks(); uint64_t delta; struct vlapic_timer *vtimer; struct hv_timer *timer; @@ -332,7 +333,7 @@ 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 now = cpu_ticks(); uint32_t remain_count = 0U; const struct vlapic_timer *vtimer; diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index 9a14e8036..195dd2567 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/hypervisor/arch/x86/timer.c b/hypervisor/arch/x86/timer.c index b4ff797f2..fc601eaa0 100644 --- a/hypervisor/arch/x86/timer.c +++ b/hypervisor/arch/x86/timer.c @@ -14,21 +14,11 @@ #include #include #include +#include #define MAX_TIMER_ACTIONS 32U -#define CAL_MS 10U #define MIN_TIMER_PERIOD_US 500U -static uint32_t tsc_khz; - -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 */ @@ -211,129 +201,6 @@ void timer_init(void) } } -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; - const 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; diff --git a/hypervisor/arch/x86/tsc.c b/hypervisor/arch/x86/tsc.c new file mode 100644 index 000000000..4f3aaec74 --- /dev/null +++ b/hypervisor/arch/x86/tsc.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#define CAL_MS 10U + +static uint32_t tsc_khz; + +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; + const 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); +} + +uint32_t get_tsc_khz(void) +{ + return tsc_khz; +} + +/* external API */ + +uint64_t cpu_ticks(void) +{ + return rdtsc(); +} + +uint32_t cpu_tickrate(void) +{ + return tsc_khz; +} diff --git a/hypervisor/arch/x86/vtd.c b/hypervisor/arch/x86/vtd.c index 8d0348adc..323ea7ea2 100644 --- a/hypervisor/arch/x86/vtd.c +++ b/hypervisor/arch/x86/vtd.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -248,11 +248,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 = cpu_ticks(); do { *status = iommu_read32(dmar_unit, offset); - ASSERT(((rdtsc() - start) < CYCLES_PER_MS), + ASSERT(((cpu_ticks() - start) < TICKS_PER_MS), "DMAR OP Timeout!"); asm_pause(); } while( (*status & mask) == pre_condition); @@ -564,9 +564,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 = cpu_ticks(); while (qi_status != DMAR_INV_STATUS_COMPLETED) { - if ((rdtsc() - start) > CYCLES_PER_MS) { + if ((cpu_ticks() - start) > TICKS_PER_MS) { pr_err("DMAR OP Timeout! @ %s", __func__); break; } diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index 710ab7ab4..6bf323509 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -24,6 +24,7 @@ #include #include #include +#include #define DBG_LEVEL_HYCALL 6U @@ -1134,7 +1135,7 @@ int32_t hcall_vm_intr_monitor(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, case INTR_CMD_DELAY_INT: /* buffer[0] is the delay time (in MS), if 0 to cancel delay */ target_vm->intr_inject_delay_delta = - intr_hdr->buffer[0] * CYCLES_PER_MS; + intr_hdr->buffer[0] * TICKS_PER_MS; break; default: diff --git a/hypervisor/common/ptdev.c b/hypervisor/common/ptdev.c index b2d482977..9c5c43b0b 100644 --- a/hypervisor/common/ptdev.c +++ b/hypervisor/common/ptdev.c @@ -12,6 +12,7 @@ #include #include #include +#include #define PTIRQ_ENTRY_HASHBITS 9U #define PTIRQ_ENTRY_HASHSIZE (1U << PTIRQ_ENTRY_HASHBITS) @@ -176,7 +177,8 @@ static void ptirq_interrupt_handler(__unused uint32_t irq, void *data) 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; + entry->intr_delay_timer.fire_tsc = + cpu_ticks() + entry->vm->intr_inject_delay_delta; } } else { entry->intr_delay_timer.fire_tsc = 0UL; diff --git a/hypervisor/common/sched_bvt.c b/hypervisor/common/sched_bvt.c index bd32467e2..3f699822b 100644 --- a/hypervisor/common/sched_bvt.c +++ b/hypervisor/common/sched_bvt.c @@ -7,6 +7,7 @@ #include #include #include +#include #define BVT_MCU_MS 1U /* context switch allowance */ @@ -148,7 +149,7 @@ static void sched_tick_handler(void *param) static int sched_bvt_init(struct sched_control *ctl) { struct sched_bvt_control *bvt_ctl = &per_cpu(sched_bvt_ctl, ctl->pcpu_id); - uint64_t tick_period = BVT_MCU_MS * CYCLES_PER_MS; + uint64_t tick_period = BVT_MCU_MS * TICKS_PER_MS; int ret = 0; ASSERT(ctl->pcpu_id == get_pcpu_id(), "Init scheduler on wrong CPU!"); @@ -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); + cpu_ticks() + tick_period, TICK_MODE_PERIODIC, tick_period); if (add_timer(&bvt_ctl->tick_timer) < 0) { pr_err("Failed to add schedule tick timer!"); @@ -180,7 +181,7 @@ static void sched_bvt_init_data(struct thread_object *obj) data = (struct sched_bvt_data *)obj->data; INIT_LIST_HEAD(&data->list); - data->mcu = BVT_MCU_MS * CYCLES_PER_MS; + data->mcu = BVT_MCU_MS * TICKS_PER_MS; /* TODO: virtual time advance ratio should be proportional to weight. */ data->vt_ratio = 1U; data->residual = 0U; @@ -200,7 +201,7 @@ 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_tsc = cpu_ticks(); uint64_t v_delta, delta_mcu = 0U; data = (struct sched_bvt_data *)obj->data; @@ -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_tsc = cpu_ticks(); uint64_t delta_mcu = 0U; if (!is_idle_thread(current)) { diff --git a/hypervisor/common/sched_iorr.c b/hypervisor/common/sched_iorr.c index deffd177f..c7339acb2 100644 --- a/hypervisor/common/sched_iorr.c +++ b/hypervisor/common/sched_iorr.c @@ -7,6 +7,7 @@ #include #include #include +#include #define CONFIG_SLICE_MS 10UL struct sched_iorr_data { @@ -77,7 +78,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 = cpu_ticks(); uint64_t rflags; obtain_schedule_lock(pcpu_id, &rflags); @@ -106,7 +107,7 @@ static void sched_tick_handler(void *param) int sched_iorr_init(struct sched_control *ctl) { struct sched_iorr_control *iorr_ctl = &per_cpu(sched_iorr_ctl, ctl->pcpu_id); - uint64_t tick_period = CYCLES_PER_MS; + uint64_t tick_period = TICKS_PER_MS; int ret = 0; ASSERT(get_pcpu_id() == ctl->pcpu_id, "Init scheduler on wrong CPU!"); @@ -116,7 +117,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); + cpu_ticks() + tick_period, TICK_MODE_PERIODIC, tick_period); if (add_timer(&iorr_ctl->tick_timer) < 0) { pr_err("Failed to add schedule tick timer!"); @@ -137,7 +138,7 @@ void sched_iorr_init_data(struct thread_object *obj) data = (struct sched_iorr_data *)obj->data; INIT_LIST_HEAD(&data->list); - data->left_cycles = data->slice_cycles = CONFIG_SLICE_MS * CYCLES_PER_MS; + data->left_cycles = data->slice_cycles = CONFIG_SLICE_MS * TICKS_PER_MS; } static struct thread_object *sched_iorr_pick_next(struct sched_control *ctl) @@ -146,7 +147,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 = cpu_ticks(); current = ctl->curr_obj; data = (struct sched_iorr_data *)current->data; diff --git a/hypervisor/common/ticks.c b/hypervisor/common/ticks.c new file mode 100644 index 000000000..9e1d796ed --- /dev/null +++ b/hypervisor/common/ticks.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +/* cpu_ticks() and cpu_tickrate() are provided in arch specific modules */ + +uint64_t us_to_ticks(uint32_t us) +{ + return (((uint64_t)us * (uint64_t)cpu_tickrate()) / 1000UL); +} + +uint64_t ticks_to_us(uint64_t ticks) +{ + uint64_t us = 0UL; + uint64_t khz = cpu_tickrate(); + + if (khz != 0U) { + us = (ticks * 1000UL) / (uint64_t)khz; + } + + return us; +} + +uint64_t ticks_to_ms(uint64_t ticks) +{ + return ticks / (uint64_t)cpu_tickrate(); +} diff --git a/hypervisor/debug/console.c b/hypervisor/debug/console.c index e1b7f5c75..40b6e0825 100644 --- a/hypervisor/debug/console.c +++ b/hypervisor/debug/console.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -161,8 +162,8 @@ void console_setup_timer(void) { uint64_t period_in_cycle, fire_tsc; - period_in_cycle = CYCLES_PER_MS * CONSOLE_KICK_TIMER_TIMEOUT; - fire_tsc = rdtsc() + period_in_cycle; + period_in_cycle = TICKS_PER_MS * CONSOLE_KICK_TIMER_TIMEOUT; + fire_tsc = cpu_ticks() + period_in_cycle; initialize_timer(&console_timer, console_timer_callback, NULL, fire_tsc, TICK_MODE_PERIODIC, period_in_cycle); diff --git a/hypervisor/debug/logmsg.c b/hypervisor/debug/logmsg.c index 2265e1825..0eb8f75f3 100644 --- a/hypervisor/debug/logmsg.c +++ b/hypervisor/debug/logmsg.c @@ -11,6 +11,7 @@ #include #include #include +#include /* buf size should be identical to the size in hvlog option, which is * transfered to SOS: @@ -53,7 +54,7 @@ void do_logmsg(uint32_t severity, const char *fmt, ...) } /* Get time-stamp value */ - timestamp = rdtsc(); + timestamp = cpu_ticks(); /* Scale time-stamp appropriately */ timestamp = ticks_to_us(timestamp); diff --git a/hypervisor/debug/profiling.c b/hypervisor/debug/profiling.c index 4a55463dc..1929aa7ad 100644 --- a/hypervisor/debug/profiling.c +++ b/hypervisor/debug/profiling.c @@ -15,6 +15,7 @@ #include #include #include +#include #define DBG_LEVEL_PROFILING 5U #define DBG_LEVEL_ERR_PROFILING 3U @@ -339,7 +340,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 = cpu_ticks(); pkt_header.collector_id = collector; pkt_header.cpu_id = get_pcpu_id(); pkt_header.data_type = 1U << type; @@ -411,7 +412,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 = cpu_ticks(); pkt_header.collector_id = collector; pkt_header.cpu_id = get_pcpu_id(); pkt_header.data_type = (uint16_t)type; @@ -1307,7 +1308,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 = cpu_ticks(); } } @@ -1323,7 +1324,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 = cpu_ticks(); get_cpu_var(profiling_info.vm_info).vmexit_reason = exit_reason; if (exit_reason == VMX_EXIT_REASON_EXTERNAL_INTERRUPT) { diff --git a/hypervisor/debug/trace.c b/hypervisor/debug/trace.c index 34b193fd9..9b1f9a57b 100644 --- a/hypervisor/debug/trace.c +++ b/hypervisor/debug/trace.c @@ -6,6 +6,7 @@ #include #include +#include #include #define TRACE_CUSTOM 0xFCU @@ -51,7 +52,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 = cpu_ticks(); entry->id = evid; entry->n_data = (uint8_t)n_data; entry->cpu = (uint8_t)cpu_id; diff --git a/hypervisor/include/arch/x86/asm/timer.h b/hypervisor/include/arch/x86/asm/timer.h index 71c5af6ac..796ec00b6 100644 --- a/hypervisor/include/arch/x86/asm/timer.h +++ b/hypervisor/include/arch/x86/asm/timer.h @@ -8,6 +8,7 @@ #define TIMER_H #include +#include /** * @brief Timer @@ -47,38 +48,8 @@ struct hv_timer { /* 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. * @@ -162,20 +133,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/arch/x86/asm/tsc.h b/hypervisor/include/arch/x86/asm/tsc.h new file mode 100644 index 000000000..47aff3524 --- /dev/null +++ b/hypervisor/include/arch/x86/asm/tsc.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ARCH_X86_TSC_H +#define ARCH_X86_TSC_H + +#include + +#define TSC_PER_MS ((uint64_t)get_tsc_khz()) + +/** + * @brief Read Time Stamp Counter (TSC). + * + * @return TSC value + */ +static inline uint64_t rdtsc(void) +{ + uint32_t lo, hi; + + asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); + return ((uint64_t)hi << 32U) | lo; +} + +/** + * @brief Get Time Stamp Counter (TSC) frequency in KHz. + * + * @return TSC frequency in KHz + */ +uint32_t get_tsc_khz(void); + +/** + * @brief Calibrate Time Stamp Counter (TSC) frequency. + * + * @return None + */ +void calibrate_tsc(void); + +#endif /* ARCH_X86_TSC_H */ diff --git a/hypervisor/include/common/ticks.h b/hypervisor/include/common/ticks.h new file mode 100644 index 000000000..0362676ea --- /dev/null +++ b/hypervisor/include/common/ticks.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef COMMON_TICKS_H +#define COMMON_TICKS_H + +#include + +#define TICKS_PER_MS us_to_ticks(1000U) + +/** + * @brief Read current CPU tick count. + * + * @return CPU ticks + */ +uint64_t cpu_ticks(void); + +/** + * @brief Get CPU tick frequency in KHz. + * + * @return CPU frequency (KHz) + */ +uint32_t cpu_tickrate(void); + +/** + * @brief Convert micro seconds to CPU ticks. + * + * @param[in] us micro seconds to convert + * @return CPU ticks + */ +uint64_t us_to_ticks(uint32_t us); + +/** + * @brief Convert CPU cycles to micro seconds. + * + * @param[in] ticks CPU ticks to convert + * @return microsecond + */ +uint64_t ticks_to_us(uint64_t ticks); + +/** + * @brief Convert CPU cycles to milli seconds. + * + * @param[in] ticks CPU ticks to convert + * @return millisecond + */ +uint64_t ticks_to_ms(uint64_t ticks); + +#endif /* COMMON_TICKS_H */ +