From 04367b942d923c29da86fb5142ddfb767394bb8a Mon Sep 17 00:00:00 2001 From: yang hang Date: Tue, 8 Feb 2022 11:56:08 +0800 Subject: [PATCH 1/4] timer: sync the host realtime to the RTC Synchronizing the host realtime to the RTC to eliminate the time value offset Signed-off-by: yang hang Signed-off-by: Bo Wan --- include/qemu-log.h | 47 +++++++ include/qemu/qemu-timer.inc.h | 31 +++++ softmmu/cpus.c | 4 + softmmu/vl.c | 3 + util/meson.build | 1 + util/qemu-log.c | 225 ++++++++++++++++++++++++++++++++++ util/qemu-timer.c | 26 ++++ 7 files changed, 337 insertions(+) create mode 100644 include/qemu-log.h create mode 100644 include/qemu/qemu-timer.inc.h create mode 100644 util/qemu-log.c diff --git a/include/qemu-log.h b/include/qemu-log.h new file mode 100644 index 0000000000..1de8c62c24 --- /dev/null +++ b/include/qemu-log.h @@ -0,0 +1,47 @@ +/* + * Introduce QEMU_LOG + * + * LOG: Introduce QEMU_LOG. + * + * Copyright (c) 2017-2020 HUAWEI TECHNOLOGIES CO.,LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef UVP_QEMU_COMMON_H +#define UVP_QEMU_COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qemu/typedefs.h" +#include "qemu/osdep.h" + +#define TIMESTAMP_MAX_LEN 33 /* RFC 3339 timestamp length shuold be 33 */ + +void qemu_get_timestamp(char *buf, int buf_size); +void qemu_convert_timestamp(struct timeval tp, char *buf, int buf_size); +void qemu_log_print(int level, const char *funcname, int linenr, + const char *fmt, ...); + +#define QEMU_LOG(level, format, ...) \ + qemu_log_print(level, __func__, __LINE__, format, ##__VA_ARGS__) + +#endif diff --git a/include/qemu/qemu-timer.inc.h b/include/qemu/qemu-timer.inc.h new file mode 100644 index 0000000000..a8e9da18c9 --- /dev/null +++ b/include/qemu/qemu-timer.inc.h @@ -0,0 +1,31 @@ +/* + * Introduce qemu-timer function + * + * We introduce the functions here to decouple for the upstream + * include/qemu/timer.h + * + * Copyright (c) 2017-2020 HUAWEI TECHNOLOGIES CO.,LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HUAWEI_INCLUDE_QEMU_QEMU_TIMER_INC_H +#define HUAWEI_INCLUDE_QEMU_QEMU_TIMER_INC_H + +#include "qemu/timer.h" + +void qemu_clock_trigger_reset(QEMUClockType type); +void qemu_clock_disable_reset(void); + +#endif /* end of include guard: HUAWEI_INCLUDE_QEMU_QEMU_TIMER_INC_H */ diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 071085f840..902a13eacb 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -45,6 +45,8 @@ #include "hw/boards.h" #include "hw/hw.h" #include "trace.h" +#include "qemu/timer.h" +#include "qemu/qemu-timer.inc.h" #ifdef CONFIG_LINUX @@ -65,6 +67,7 @@ #endif /* CONFIG_LINUX */ static QemuMutex qemu_global_mutex; +extern QEMUClockType rtc_clock; bool cpu_is_stopped(CPUState *cpu) { @@ -683,6 +686,7 @@ int vm_prepare_start(void) return -1; } + qemu_clock_trigger_reset(rtc_clock); /* We are sending this now, but the CPUs will be resumed shortly later */ qapi_event_send_resume(); diff --git a/softmmu/vl.c b/softmmu/vl.c index d9e4c619d3..bec3eedc90 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -126,6 +126,7 @@ #include "qapi/qmp/qerror.h" #include "sysemu/iothread.h" #include "qemu/guest-random.h" +#include "qemu/qemu-timer.inc.h" #include "config-host.h" @@ -3504,6 +3505,8 @@ void qemu_init(int argc, char **argv, char **envp) runstate_set(RUN_STATE_INMIGRATE); } incoming = optarg; + + qemu_clock_disable_reset(); break; case QEMU_OPTION_only_migratable: only_migratable = 1; diff --git a/util/meson.build b/util/meson.build index 05b593055a..2674383806 100644 --- a/util/meson.build +++ b/util/meson.build @@ -80,6 +80,7 @@ if have_block util_ss.add(files('qemu-coroutine-sleep.c')) util_ss.add(files('qemu-co-shared-resource.c')) util_ss.add(files('thread-pool.c', 'qemu-timer.c')) + util_ss.add(files('qemu-log.c')) util_ss.add(files('readline.c')) util_ss.add(files('throttle.c')) util_ss.add(files('timed-average.c')) diff --git a/util/qemu-log.c b/util/qemu-log.c new file mode 100644 index 0000000000..31379bfa78 --- /dev/null +++ b/util/qemu-log.c @@ -0,0 +1,225 @@ +/* + * Introduce QEMU_LOG + * + * LOG: Introduce QEMU_LOG. + * + * Copyright (c) 2017-2020 HUAWEI TECHNOLOGIES CO.,LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu-log.h" +#include +#include "qemu/osdep.h" + +#define BEGIN_YEAR 1900 +#define DEFAULT_SECFRACPRECISION 6 +#define LOG_LEVEL_NAME_MAX_LEN 10 + +static const int tenPowers[6] = { 1, 10, 100, 1000, 10000, 100000 }; + +typedef char intTiny; + +struct syslogTime { + intTiny timeType; /* 0 - unitinialized + * 1 - RFC 3164 + * 2 - syslog-protocol + */ + intTiny month; + intTiny day; + intTiny hour; /* 24 hour clock */ + intTiny minute; + intTiny second; + intTiny secfracPrecision; + intTiny OffsetMinute; /* UTC offset in minutes */ + intTiny OffsetHour; /* UTC offset in hours + * full UTC offset minutes + * = OffsetHours*60 + OffsetMinute. + * Then use OffsetMode to know the direction. + */ + char OffsetMode; /* UTC offset + or - */ + short year; + int secfrac; /* fractional seconds (must be 32 bit!) */ + intTiny inUTC; /* forced UTC? */ +}; +typedef struct syslogTime syslogTime_t; + +typedef struct syslogName_s { + const char *c_name; + int c_val; +} syslogName_t; + +static syslogName_t syslogPriNames[] = { + {"emerg", LOG_EMERG}, + {"alert", LOG_ALERT}, + {"crit", LOG_CRIT}, + {"err", LOG_ERR}, + {"warning", LOG_WARNING}, + {"notice", LOG_NOTICE}, + {"info", LOG_INFO}, + {"debug", LOG_DEBUG}, + {NULL, -1} +}; + +/** + * Format a syslogTimestamp to a RFC3339 timestamp string (as + * specified in syslog-protocol). + * + * Notes: rfc_time_buf size >= TIMESTAMP_MAX_LEN + */ +static void formatTimestamp3339(struct syslogTime *ts, char *rfc_time_buf) +{ + int iBuf = 0; + int power = 0; + int secfrac = 0; + short digit = 0; + char *pBuf = rfc_time_buf; + + pBuf[iBuf++] = (ts->year / 1000) % 10 + '0'; + pBuf[iBuf++] = (ts->year / 100) % 10 + '0'; + pBuf[iBuf++] = (ts->year / 10) % 10 + '0'; + pBuf[iBuf++] = ts->year % 10 + '0'; + pBuf[iBuf++] = '-'; + /* month */ + pBuf[iBuf++] = (ts->month / 10) % 10 + '0'; + pBuf[iBuf++] = ts->month % 10 + '0'; + pBuf[iBuf++] = '-'; + /* day */ + pBuf[iBuf++] = (ts->day / 10) % 10 + '0'; + pBuf[iBuf++] = ts->day % 10 + '0'; + pBuf[iBuf++] = 'T'; + /* hour */ + pBuf[iBuf++] = (ts->hour / 10) % 10 + '0'; + pBuf[iBuf++] = ts->hour % 10 + '0'; + pBuf[iBuf++] = ':'; + /* minute */ + pBuf[iBuf++] = (ts->minute / 10) % 10 + '0'; + pBuf[iBuf++] = ts->minute % 10 + '0'; + pBuf[iBuf++] = ':'; + /* second */ + pBuf[iBuf++] = (ts->second / 10) % 10 + '0'; + pBuf[iBuf++] = ts->second % 10 + '0'; + + if (ts->secfracPrecision > 0) { + pBuf[iBuf++] = '.'; + power = tenPowers[(ts->secfracPrecision - 1) % 6]; + secfrac = ts->secfrac; + while (power > 0) { + digit = secfrac / power; + secfrac -= digit * power; + power /= 10; + pBuf[iBuf++] = digit + '0'; + } + } + + pBuf[iBuf++] = ts->OffsetMode; + pBuf[iBuf++] = (ts->OffsetHour / 10) % 10 + '0'; + pBuf[iBuf++] = ts->OffsetHour % 10 + '0'; + pBuf[iBuf++] = ':'; + pBuf[iBuf++] = (ts->OffsetMinute / 10) % 10 + '0'; + pBuf[iBuf++] = ts->OffsetMinute % 10 + '0'; + + pBuf[iBuf] = '\0'; +} + +void qemu_convert_timestamp(struct timeval tp, char *buf, int buf_size) +{ + struct tm *tm; + struct tm tmBuf; + long lBias = 0; + time_t secs; + syslogTime_t ts; + char rfc_time_buf[TIMESTAMP_MAX_LEN] = {0}; + + /* RFC 3339 timestamp length must be greater than or equal 33 */ + if (buf_size < TIMESTAMP_MAX_LEN) { + buf[0] = '\0'; + (void)printf("RFC 3339 timestamp length must be greater than or equal 33\n"); + return; + } + + secs = tp.tv_sec; + tm = localtime_r(&secs, &tmBuf); + + ts.year = tm->tm_year + BEGIN_YEAR; + ts.month = tm->tm_mon + 1; + ts.day = tm->tm_mday; + ts.hour = tm->tm_hour; + ts.minute = tm->tm_min; + ts.second = tm->tm_sec; + ts.secfrac = tp.tv_usec; + ts.secfracPrecision = DEFAULT_SECFRACPRECISION; + + lBias = tm->tm_gmtoff; + if (lBias < 0) { + ts.OffsetMode = '-'; + lBias *= -1; + } else { + ts.OffsetMode = '+'; + } + + ts.OffsetHour = lBias / 3600; + ts.OffsetMinute = (lBias % 3600) / 60; + + formatTimestamp3339(&ts, rfc_time_buf); + (void)snprintf(buf, buf_size, "%s", rfc_time_buf); +} + +void qemu_get_timestamp(char *buf, int buf_size) +{ + struct timeval tp; + (void)gettimeofday(&tp, NULL); + + qemu_convert_timestamp(tp, buf, buf_size); +} + + +static void qemu_get_loglevelname(int level, char *log_level_name, int len) +{ + syslogName_t *c; + + for (c = syslogPriNames; c->c_name; c++) { + if (level == c->c_val) { + (void)snprintf(log_level_name, len, "%s", c->c_name); + return; + } + } + + (void)printf("The log level is wrong\n"); +} + +void qemu_log_print(int level, const char *funcname, int linenr, + const char *fmt, ...) +{ + va_list ap; + char time_buf[TIMESTAMP_MAX_LEN] = {0}; + char log_level_name[LOG_LEVEL_NAME_MAX_LEN] = {0}; + char buf[1024] = {0}; + + qemu_get_timestamp(time_buf, TIMESTAMP_MAX_LEN); + qemu_get_loglevelname(level, log_level_name, sizeof(log_level_name)); + + va_start(ap, fmt); + (void)vsnprintf(buf, 1024, fmt, ap); + va_end(ap); + + if (funcname != NULL) { + (void)fprintf(stderr, "%s|%s|qemu[%d]|[%d]|%s[%d]|: %s", time_buf, + log_level_name, getpid(), qemu_get_thread_id(), + funcname, linenr, buf); + } else { + (void)fprintf(stderr, "%s|%s|qemu[%d]|[%d]|%s", time_buf, log_level_name, + getpid(), qemu_get_thread_id(), buf); + } +} diff --git a/util/qemu-timer.c b/util/qemu-timer.c index f36c75e594..ed888d91e0 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -29,6 +29,8 @@ #include "sysemu/cpu-timers.h" #include "sysemu/replay.h" #include "sysemu/cpus.h" +#include "qemu-log.h" +#include "qemu/qemu-timer.inc.h" #ifdef CONFIG_POSIX #include @@ -44,11 +46,15 @@ /***********************************************************/ /* timers */ +bool g_vm_cold_start_flag = true; typedef struct QEMUClock { /* We rely on BQL to protect the timerlists */ QLIST_HEAD(, QEMUTimerList) timerlists; + NotifierList reset_notifiers; + int64_t last; + QEMUClockType type; bool enabled; } QEMUClock; @@ -672,3 +678,23 @@ bool qemu_clock_run_all_timers(void) return progress; } + +void qemu_clock_disable_reset(void) +{ + g_vm_cold_start_flag = false; +} + +void qemu_clock_trigger_reset(QEMUClockType type) +{ + if (!g_vm_cold_start_flag) { + return; + } + if (type == QEMU_CLOCK_VIRTUAL) { + int64_t now; + QEMUClock *clock = qemu_clock_ptr(type); + now = REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime()); + notifier_list_notify(&clock->reset_notifiers, &now); + QEMU_LOG(LOG_INFO, "Guest synchronise time success.\n"); + } + g_vm_cold_start_flag = false; +} -- Gitee From a4d81c68e81c5b9be81b57efc5f09997b7f8df35 Mon Sep 17 00:00:00 2001 From: yang hang Date: Tue, 8 Feb 2022 14:35:20 +0800 Subject: [PATCH 2/4] timer: rtc irqs reinject in kvm The rtc is emulated in qemu but coalesced irqs are reinjected by kvm Signed-off-by: yang hang Signed-off-by: Bo Wan --- accel/kvm/kvm-all.c | 8 +++++ hw/rtc/mc146818rtc.c | 26 +++++++++++++- hw/timer/meson.build | 1 + hw/timer/rtc.c | 66 +++++++++++++++++++++++++++++++++++ include/hw/timer/rtc.h | 52 +++++++++++++++++++++++++++ include/qemu/qemu-timer.inc.h | 6 ++-- 6 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 hw/timer/rtc.c create mode 100644 include/hw/timer/rtc.h diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index eecd8031cf..52304ab9bb 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -53,6 +53,8 @@ #include #endif +#include "hw/timer/rtc.h" + /* KVM uses PAGE_SIZE in its definition of KVM_COALESCED_MMIO_MAX. We * need to use the real host PAGE_SIZE, as that's what KVM will use. */ @@ -170,6 +172,7 @@ bool kvm_ioeventfd_any_length_allowed; bool kvm_msi_use_devid; static bool kvm_immediate_exit; static hwaddr kvm_max_slot_size = ~0; +bool kvm_rtc_reinject_enable; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -2581,6 +2584,11 @@ static int kvm_init(MachineState *ms) kvm_irqchip_create(s); } + kvm_rtc_reinject_enable = (kvm_check_extension(kvm_state, KVM_CAP_RTC_IRQ_COALESCED) > 0); + if (!kvm_rtc_reinject_enable) { + QEMU_LOG(LOG_INFO, "kvm rtc irq reinjection not supported.\n"); + } + if (kvm_eventfds_allowed) { s->memory_listener.listener.eventfd_add = kvm_mem_ioeventfd_add; s->memory_listener.listener.eventfd_del = kvm_mem_ioeventfd_del; diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 4fbafddb22..b355588d6c 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -42,7 +42,7 @@ #include "qapi/error.h" #include "qapi/qapi-events-misc-target.h" #include "qapi/visitor.h" -#include "hw/rtc/mc146818rtc_regs.h" +#include "hw/timer/rtc.h" #ifdef TARGET_I386 #include "qapi/qapi-commands-misc-target.h" @@ -217,9 +217,17 @@ periodic_timer_update(RTCState *s, int64_t current_time, uint32_t old_period, bo */ if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { uint32_t old_irq_coalesced = s->irq_coalesced; + if (kvm_rtc_reinject_enable) { + old_irq_coalesced += rtc_get_coalesced_irq(); + } lost_clock += old_irq_coalesced * old_period; s->irq_coalesced = lost_clock / s->period; + if (kvm_rtc_reinject_enable) { + rtc_set_coalesced_irq(s->irq_coalesced); + s->irq_coalesced = 0; + old_irq_coalesced = 0; + } lost_clock %= s->period; if (old_irq_coalesced != s->irq_coalesced || old_period != s->period) { @@ -784,6 +792,11 @@ static int rtc_pre_save(void *opaque) rtc_update_time(s); + if (kvm_rtc_reinject_enable && + s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { + s->irq_coalesced += rtc_get_coalesced_irq(); + } + return 0; } @@ -815,6 +828,13 @@ static int rtc_post_load(void *opaque, int version_id) rtc_coalesced_timer_update(s); } } + + if (kvm_rtc_reinject_enable && s->irq_coalesced != 0 && + s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { + rtc_set_coalesced_irq(s->irq_coalesced); + s->irq_coalesced = 0; + } + return 0; } @@ -949,6 +969,10 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) object_property_add_tm(OBJECT(s), "date", rtc_get_date); qdev_init_gpio_out(dev, &s->irq, 1); + if (kvm_rtc_reinject_enable && + s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { + rtc_lost_tick_policy_slew(); + } QLIST_INSERT_HEAD(&rtc_devices, s, link); } diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 03092e2ceb..785fb6825b 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -36,5 +36,6 @@ softmmu_ss.add(when: 'CONFIG_STM32F2XX_TIMER', if_true: files('stm32f2xx_timer.c softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_timer.c')) specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_timer.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_PWM', if_true: files('sifive_pwm.c')) +softmmu_ss.add(files('rtc.c')) specific_ss.add(when: 'CONFIG_AVR_TIMER16', if_true: files('avr_timer16.c')) diff --git a/hw/timer/rtc.c b/hw/timer/rtc.c new file mode 100644 index 0000000000..52ef44f1f8 --- /dev/null +++ b/hw/timer/rtc.c @@ -0,0 +1,66 @@ + /* + * QEMU rtc + * + * We introduce the functions here to decouple for the upstream + * hw/timer/mc146818rtc.c + * + * Copyright (c) 2017-2020 HUAWEI TECHNOLOGIES CO.,LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include +#include "qemu/osdep.h" +#include "hw/timer/rtc.h" +#include "sysemu/kvm.h" + +extern int kvm_vm_ioctl(KVMState *s, int type, ...); + +uint32_t rtc_get_coalesced_irq(void) +{ + struct kvm_rtc_reinject_control control = {}; + int ret; + + control.flag = KVM_GET_RTC_IRQ_COALESCED; + ret = kvm_vm_ioctl(kvm_state, KVM_RTC_REINJECT_CONTROL, &control); + if (ret < 0) { + QEMU_LOG(LOG_ERR, "Failed to get coalesced irqs from kmod: %d\n", ret); + } + return control.rtc_irq_coalesced; +} + +void rtc_set_coalesced_irq(uint32_t nr_irqs) +{ + struct kvm_rtc_reinject_control control = {}; + int ret; + + control.rtc_irq_coalesced = nr_irqs; + control.flag = KVM_SET_RTC_IRQ_COALESCED; + ret = kvm_vm_ioctl(kvm_state, KVM_RTC_REINJECT_CONTROL, &control); + if (ret < 0) { + QEMU_LOG(LOG_ERR, "Failed to set coalesced irqs to kmod: %d, %u\n", ret, nr_irqs); + } +} + +void rtc_lost_tick_policy_slew(void) +{ + struct kvm_rtc_reinject_control control = {}; + int ret; + + control.flag = KVM_RTC_LOST_TICK_POLICY_SLEW; + ret = kvm_vm_ioctl(kvm_state, KVM_RTC_REINJECT_CONTROL, &control); + if (ret < 0) { + QEMU_LOG(LOG_ERR, "Failed to notify kvm to use lost tick policy slew: %d\n", ret); + } +} diff --git a/include/hw/timer/rtc.h b/include/hw/timer/rtc.h new file mode 100644 index 0000000000..04b942de86 --- /dev/null +++ b/include/hw/timer/rtc.h @@ -0,0 +1,52 @@ +/* +* QEMU rtc +* +* We introduce the functions here to decouple for the upstream +* include/hw/timer/mc146818rtc.h +* +* Copyright (c) 2017-2020 HUAWEI TECHNOLOGIES CO.,LTD. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License along +* with this program; if not, see . +*/ + +#ifndef INCLUDE_HW_TIMER_RTC_H +#define INCLUDE_HW_TIMER_RTC_H + +#include +#include +#include +#include "qemu-log.h" + +/* flags to control coalesced irq */ +#define KVM_GET_RTC_IRQ_COALESCED (1 << 0) +#define KVM_SET_RTC_IRQ_COALESCED (1 << 1) +#define KVM_RTC_LOST_TICK_POLICY_SLEW (1 << 2) + +/* RTC is emulated in qemu, but the colasced irqs are reinjected in kvm */ +#define KVM_CAP_RTC_IRQ_COALESCED 163 +#define KVM_RTC_REINJECT_CONTROL _IOWR(KVMIO, 0x56, struct kvm_rtc_reinject_control) + +struct kvm_rtc_reinject_control { + __u32 rtc_irq_coalesced; + __u8 flag; + __u8 reserved[31]; +}; + +extern bool kvm_rtc_reinject_enable; + +uint32_t rtc_get_coalesced_irq(void); +void rtc_set_coalesced_irq(uint32_t nr_irqs); +void rtc_lost_tick_policy_slew(void); + +#endif diff --git a/include/qemu/qemu-timer.inc.h b/include/qemu/qemu-timer.inc.h index a8e9da18c9..bbe7b67f7a 100644 --- a/include/qemu/qemu-timer.inc.h +++ b/include/qemu/qemu-timer.inc.h @@ -20,12 +20,12 @@ * with this program; if not, see . */ -#ifndef HUAWEI_INCLUDE_QEMU_QEMU_TIMER_INC_H -#define HUAWEI_INCLUDE_QEMU_QEMU_TIMER_INC_H +#ifndef INCLUDE_QEMU_QEMU_TIMER_INC_H +#define INCLUDE_QEMU_QEMU_TIMER_INC_H #include "qemu/timer.h" void qemu_clock_trigger_reset(QEMUClockType type); void qemu_clock_disable_reset(void); -#endif /* end of include guard: HUAWEI_INCLUDE_QEMU_QEMU_TIMER_INC_H */ +#endif /* end of include guard: INCLUDE_QEMU_QEMU_TIMER_INC_H */ -- Gitee From f66688a99bed38d9ab7c039d79b27d15c943811d Mon Sep 17 00:00:00 2001 From: yang hang Date: Wed, 9 Feb 2022 14:26:10 +0800 Subject: [PATCH 3/4] timer: set rtc cachup speed for per vm Supports setting the RTC clock compensation rate in kernel mode with virtual machine as granularity, instead of using the same speed for all virtual machines. A new configuration item catchup speed is added to libvirt to set the compensation rate of virtual machine Signed-off-by: yang hang Signed-off-by: Bo Wan --- hw/rtc/mc146818rtc.c | 15 +++++++++++++++ hw/timer/rtc.c | 29 +++++++++++++++++++++++++++++ include/hw/timer/rtc.h | 6 +++++- qapi/misc-target.json | 12 ++++++++++++ qapi/pragma.json | 3 ++- softmmu/vl.c | 3 +++ 6 files changed, 66 insertions(+), 2 deletions(-) diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index b355588d6c..f1ae63300d 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -110,6 +110,21 @@ static void rtc_coalesced_timer_update(RTCState *s) static QLIST_HEAD(, RTCState) rtc_devices = QLIST_HEAD_INITIALIZER(rtc_devices); +void qmp_set_rtc_catchup_speed(const uint32_t speed, Error **errp) +{ + RTCState *s; + + if (!kvm_rtc_reinject_enable) { + return; + } + + QLIST_FOREACH(s, &rtc_devices, link) { + if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { + set_rtc_catchup_speed(speed); + } + } +} + #ifdef TARGET_I386 void qmp_rtc_reset_reinjection(Error **errp) { diff --git a/hw/timer/rtc.c b/hw/timer/rtc.c index 52ef44f1f8..3f50e8b892 100644 --- a/hw/timer/rtc.c +++ b/hw/timer/rtc.c @@ -24,6 +24,8 @@ #include "qemu/osdep.h" #include "hw/timer/rtc.h" #include "sysemu/kvm.h" +#include "qemu/config-file.h" +#include "qemu/option.h" extern int kvm_vm_ioctl(KVMState *s, int type, ...); @@ -64,3 +66,30 @@ void rtc_lost_tick_policy_slew(void) QEMU_LOG(LOG_ERR, "Failed to notify kvm to use lost tick policy slew: %d\n", ret); } } + +uint32_t rtc_catchup_speed(void) +{ + uint32_t speed; + QemuOpts *opts = qemu_find_opts_singleton("rtc"); + + speed = qemu_opt_get_number(opts, "speed", 0); + QEMU_LOG(LOG_INFO, "rtc catchup speed: %u\n", speed); + + return speed; +} + +void set_rtc_catchup_speed(const uint32_t speed) +{ + struct kvm_rtc_reinject_control control = {}; + int ret; + + if (speed > 0) { + control.flag = KVM_SET_RTC_CATCHUP_SPEED; + control.speed = speed; + ret = kvm_vm_ioctl(kvm_state, KVM_RTC_REINJECT_CONTROL, &control); + if (ret < 0) { + QEMU_LOG(LOG_ERR, "Failed to set rtc_catchup_speed: %d\n", ret); + } + QEMU_LOG(LOG_INFO, "Success to set rtc_catchup_speed: %u\n", speed); + } +} diff --git a/include/hw/timer/rtc.h b/include/hw/timer/rtc.h index 04b942de86..2d064d2994 100644 --- a/include/hw/timer/rtc.h +++ b/include/hw/timer/rtc.h @@ -32,6 +32,7 @@ #define KVM_GET_RTC_IRQ_COALESCED (1 << 0) #define KVM_SET_RTC_IRQ_COALESCED (1 << 1) #define KVM_RTC_LOST_TICK_POLICY_SLEW (1 << 2) +#define KVM_SET_RTC_CATCHUP_SPEED (1 << 3) /* RTC is emulated in qemu, but the colasced irqs are reinjected in kvm */ #define KVM_CAP_RTC_IRQ_COALESCED 163 @@ -40,7 +41,8 @@ struct kvm_rtc_reinject_control { __u32 rtc_irq_coalesced; __u8 flag; - __u8 reserved[31]; + __u8 speed; + __u8 reserved[30]; }; extern bool kvm_rtc_reinject_enable; @@ -48,5 +50,7 @@ extern bool kvm_rtc_reinject_enable; uint32_t rtc_get_coalesced_irq(void); void rtc_set_coalesced_irq(uint32_t nr_irqs); void rtc_lost_tick_policy_slew(void); +uint32_t rtc_catchup_speed(void); +void set_rtc_catchup_speed(const uint32_t speed); #endif diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 5aa2b95b7d..3467a019bc 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -54,6 +54,18 @@ { 'command': 'rtc-reset-reinjection', 'if': 'TARGET_I386' } +## +# @set-rtc-catchup-speed: +# +# set rtc catchup speed +# +# @speed: rtc catchup speed +# +# Returns: Nothing on success +# +# Since: 2.8.1 +## +{ 'command': 'set-rtc-catchup-speed', 'data': {'speed': 'uint32'}} ## # @SevState: diff --git a/qapi/pragma.json b/qapi/pragma.json index 3bc0335d1f..d546f1ab49 100644 --- a/qapi/pragma.json +++ b/qapi/pragma.json @@ -20,7 +20,8 @@ 'set_password', 'system_powerdown', 'system_reset', - 'system_wakeup' ], + 'system_wakeup', + 'set-rtc-catchup-speed' ], 'command-returns-exceptions': [ 'human-monitor-command', 'qom-get', diff --git a/softmmu/vl.c b/softmmu/vl.c index bec3eedc90..381f9a61d8 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -228,6 +228,9 @@ static QemuOptsList qemu_rtc_opts = { },{ .name = "driftfix", .type = QEMU_OPT_STRING, + },{ + .name = "speed", + .type = QEMU_OPT_NUMBER, }, { /* end of list */ } }, -- Gitee From b24197cd51c94639ac82bb2934b7653cd6f9ec55 Mon Sep 17 00:00:00 2001 From: yang hang Date: Tue, 8 Feb 2022 19:39:57 +0800 Subject: [PATCH 4/4] timer: qmp_set_rtc_catchup_speed only used in x86 qmp_set_rtc_catchup_speed only used in x86 Signed-off-by: yang hang Signed-off-by: Bo Wan --- hw/rtc/mc146818rtc.c | 2 +- qapi/misc-target.json | 2 +- qemu.spec | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 qemu.spec diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index f1ae63300d..afe082f687 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -110,6 +110,7 @@ static void rtc_coalesced_timer_update(RTCState *s) static QLIST_HEAD(, RTCState) rtc_devices = QLIST_HEAD_INITIALIZER(rtc_devices); +#ifdef TARGET_I386 void qmp_set_rtc_catchup_speed(const uint32_t speed, Error **errp) { RTCState *s; @@ -125,7 +126,6 @@ void qmp_set_rtc_catchup_speed(const uint32_t speed, Error **errp) } } -#ifdef TARGET_I386 void qmp_rtc_reset_reinjection(Error **errp) { RTCState *s; diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 3467a019bc..ac7f7bf43a 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -65,7 +65,7 @@ # # Since: 2.8.1 ## -{ 'command': 'set-rtc-catchup-speed', 'data': {'speed': 'uint32'}} +{ 'command': 'set-rtc-catchup-speed', 'data': {'speed': 'uint32'}, 'if': 'TARGET_I386'} ## # @SevState: diff --git a/qemu.spec b/qemu.spec new file mode 100644 index 0000000000..ae9e0f3939 --- /dev/null +++ b/qemu.spec @@ -0,0 +1,35 @@ +Name: +Version: +Release: 1%{?dist} +Summary: + +Group: +License: +URL: +Source0: + +BuildRequires: +Requires: + +%description + + +%prep +%setup -q + + +%build +%configure +make %{?_smp_mflags} + + +%install +%make_install + + +%files +%doc + + + +%changelog -- Gitee