qemu时钟虚拟化
虚拟机启动参数-rtc base=localtime,driftfix=slew(gdb) bt#0 0x00005555558f3184 in mc146818_rtc_init (bus=0x555557057dd0, base_year=2000, intercept_irq=0x0) at /home/work/qemu/hw/rtc/mc146818rtc.c:981#1 0x00005
虚拟机启动参数
-rtc base=localtime,driftfix=slew
(gdb) bt
#0 0x00005555558f3184 in mc146818_rtc_init (bus=0x555557057dd0, base_year=2000, intercept_irq=0x0) at /home/work/qemu/hw/rtc/mc146818rtc.c:981
#1 0x0000555555945707 in pc_basic_device_init (pcms=0x555556a828a0, isa_bus=0x555557057dd0, gsi=0x555556cb66a0, rtc_state=0x7fffffffcf30, create_fdctrl=true, hpet_irqs=4) at /home/work/qemu/hw/i386/pc.c:1209
#2 0x0000555555949420 in pc_init1 (machine=0x555556a828a0, host_type=0x555555f7b5be "i440FX-pcihost", pci_type=0x555555f7b5b7 "i440FX") at /home/work/qemu/hw/i386/pc_piix.c:241
#3 0x0000555555949b38 in pc_init_v5_1 (machine=0x555556a828a0) at /home/work/qemu/hw/i386/pc_piix.c:438
#4 0x0000555555ab289c in machine_run_board_init (machine=0x555556a828a0) at hw/core/machine.c:1134
#5 0x000055555599a506 in qemu_init (argc=91, argv=0x7fffffffd3d8, envp=0x7fffffffd6b8) at /home/work/qemu/softmmu/vl.c:4356
#6 0x0000555555de7941 in main (argc=91, argv=0x7fffffffd3d8, envp=0x7fffffffd6b8) at /home/work/qemu/softmmu/main.c:48
--> isa_realize_and_unref
softmmu/vl.c
--> configure_rtc(qemu_find_opts_singleton("rtc"))
static void configure_rtc(QemuOpts *opts)
{
const char *value;
/* Set defaults */
rtc_clock = QEMU_CLOCK_HOST;
rtc_ref_start_datetime = qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000;
rtc_realtime_clock_offset = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000;
......
value = qemu_opt_get(opts, "driftfix");
if (value) {
if (!strcmp(value, "slew")) {
object_register_sugar_prop("mc146818rtc", //模拟mc146818时钟芯片
"lost_tick_policy",
"slew");
} else if (!strcmp(value, "none")) {
/* discard is default */
} else {
error_report("invalid option value '%s'", value);
exit(1);
}
}
}
模拟mc146818时钟芯片
hw/rtc/mc146818rtc.c
--> type_init(mc146818rtc_register_types)
--> c->realize = rtc_realizefn;
static void rtc_realizefn(DeviceState *dev, Error **errp)
{
ISADevice *isadev = ISA_DEVICE(dev);
RTCState *s = MC146818_RTC(dev);
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
/* This is for historical reasons. The default base year qdev property
* was set to 2000 for most machine types before the century byte was
* implemented.
*
* This if statement means that the century byte will be always 0
* (at least until 2079...) for base_year = 1980, but will be set
* correctly for base_year = 2000.
*/
if (s->base_year == 2000) {
s->base_year = 0;
}
rtc_set_date_from_host(isadev); //获取服务器主机的时间
switch (s->lost_tick_policy) {
#ifdef TARGET_I386
case LOST_TICK_POLICY_SLEW:
s->coalesced_timer =
timer_new_ns(rtc_clock, rtc_coalesced_timer, s);
break;
#endif
case LOST_TICK_POLICY_DISCARD:
break;
default:
error_setg(errp, "Invalid lost tick policy.");
return;
}
s->periodic_timer = timer_new_ns(rtc_clock, rtc_periodic_timer, s);
s->update_timer = timer_new_ns(rtc_clock, rtc_update_timer, s);
check_update_timer(s);
s->suspend_notifier.notify = rtc_notify_suspend;
qemu_register_suspend_notifier(&s->suspend_notifier);
memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2);
isa_register_ioport(isadev, &s->io, RTC_ISA_BASE);
/* register rtc 0x70 port for coalesced_pio */
memory_region_set_flush_coalesced(&s->io);
memory_region_init_io(&s->coalesced_io, OBJECT(s), &cmos_ops,
s, "rtc-index", 1);
memory_region_add_subregion(&s->io, 0, &s->coalesced_io);
memory_region_add_coalescing(&s->coalesced_io, 0, 1);
qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3);
qemu_register_reset(rtc_reset, s);
object_property_add_tm(OBJECT(s), "date", rtc_get_date);
qdev_init_gpio_out(dev, &s->irq, 1);
QLIST_INSERT_HEAD(&rtc_devices, s, link);
}
---------------------------------------------------------------------------------------
/**
* QEMUClockType:
*
* The following clock types are available:
*
* @QEMU_CLOCK_REALTIME: Real time clock
*
* The real time clock should be used only for stuff which does not
* change the virtual machine state, as it runs even if the virtual
* machine is stopped.
*
* @QEMU_CLOCK_VIRTUAL: virtual clock
*
* The virtual clock only runs during the emulation. It stops
* when the virtual machine is stopped.
*
* @QEMU_CLOCK_HOST: host clock
*
* The host clock should be used for device models that emulate accurate
* real time sources. It will continue to run when the virtual machine
* is suspended, and it will reflect system time changes the host may
* undergo (e.g. due to NTP).
*
* @QEMU_CLOCK_VIRTUAL_RT: realtime clock used for icount warp
*
* Outside icount mode, this clock is the same as @QEMU_CLOCK_VIRTUAL.
* In icount mode, this clock counts nanoseconds while the virtual
* machine is running. It is used to increase @QEMU_CLOCK_VIRTUAL
* while the CPUs are sleeping and thus not executing instructions.
*/
typedef enum {
QEMU_CLOCK_REALTIME = 0,
QEMU_CLOCK_VIRTUAL = 1,
QEMU_CLOCK_HOST = 2,
QEMU_CLOCK_VIRTUAL_RT = 3,
QEMU_CLOCK_MAX
} QEMUClockType;
typedef struct RTCState {
ISADevice parent_obj;
MemoryRegion io;
MemoryRegion coalesced_io;
uint8_t cmos_data[128];
uint8_t cmos_index;
int32_t base_year;
uint64_t base_rtc;
uint64_t last_update;
int64_t offset;
qemu_irq irq;
int it_shift;
/* periodic timer */
QEMUTimer *periodic_timer;
int64_t next_periodic_time;
/* update-ended timer */
QEMUTimer *update_timer;
uint64_t next_alarm_time;
uint16_t irq_reinject_on_ack_count;
uint32_t irq_coalesced;
uint32_t period;
QEMUTimer *coalesced_timer;
Notifier clock_reset_notifier;
LostTickPolicy lost_tick_policy;
Notifier suspend_notifier;
QLIST_ENTRY(RTCState) link;
} RTCState;
int64_t qemu_clock_get_ns(QEMUClockType type)
{
switch (type) {
case QEMU_CLOCK_REALTIME:
return get_clock();
default:
case QEMU_CLOCK_VIRTUAL:
if (use_icount) {
return cpu_get_icount();
} else {
return cpu_get_clock();
}
case QEMU_CLOCK_HOST:
return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
case QEMU_CLOCK_VIRTUAL_RT:
return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock());
}
}
更多推荐
所有评论(0)