qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cpu-timers.c (8113B)


      1 /*
      2  * QEMU System Emulator
      3  *
      4  * Copyright (c) 2003-2008 Fabrice Bellard
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "qemu/cutils.h"
     27 #include "migration/vmstate.h"
     28 #include "qapi/error.h"
     29 #include "qemu/error-report.h"
     30 #include "sysemu/cpus.h"
     31 #include "qemu/main-loop.h"
     32 #include "qemu/option.h"
     33 #include "qemu/seqlock.h"
     34 #include "sysemu/replay.h"
     35 #include "sysemu/runstate.h"
     36 #include "hw/core/cpu.h"
     37 #include "sysemu/cpu-timers.h"
     38 #include "sysemu/cpu-throttle.h"
     39 #include "timers-state.h"
     40 
     41 /* clock and ticks */
     42 
     43 static int64_t cpu_get_ticks_locked(void)
     44 {
     45     int64_t ticks = timers_state.cpu_ticks_offset;
     46     if (timers_state.cpu_ticks_enabled) {
     47         ticks += cpu_get_host_ticks();
     48     }
     49 
     50     if (timers_state.cpu_ticks_prev > ticks) {
     51         /* Non increasing ticks may happen if the host uses software suspend. */
     52         timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
     53         ticks = timers_state.cpu_ticks_prev;
     54     }
     55 
     56     timers_state.cpu_ticks_prev = ticks;
     57     return ticks;
     58 }
     59 
     60 /*
     61  * return the time elapsed in VM between vm_start and vm_stop.
     62  * cpu_get_ticks() uses units of the host CPU cycle counter.
     63  */
     64 int64_t cpu_get_ticks(void)
     65 {
     66     int64_t ticks;
     67 
     68     qemu_spin_lock(&timers_state.vm_clock_lock);
     69     ticks = cpu_get_ticks_locked();
     70     qemu_spin_unlock(&timers_state.vm_clock_lock);
     71     return ticks;
     72 }
     73 
     74 int64_t cpu_get_clock_locked(void)
     75 {
     76     int64_t time;
     77 
     78     time = timers_state.cpu_clock_offset;
     79     if (timers_state.cpu_ticks_enabled) {
     80         time += get_clock();
     81     }
     82 
     83     return time;
     84 }
     85 
     86 /*
     87  * Return the monotonic time elapsed in VM, i.e.,
     88  * the time between vm_start and vm_stop
     89  */
     90 int64_t cpu_get_clock(void)
     91 {
     92     int64_t ti;
     93     unsigned start;
     94 
     95     do {
     96         start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
     97         ti = cpu_get_clock_locked();
     98     } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
     99 
    100     return ti;
    101 }
    102 
    103 /*
    104  * enable cpu_get_ticks()
    105  * Caller must hold BQL which serves as mutex for vm_clock_seqlock.
    106  */
    107 void cpu_enable_ticks(void)
    108 {
    109     seqlock_write_lock(&timers_state.vm_clock_seqlock,
    110                        &timers_state.vm_clock_lock);
    111     if (!timers_state.cpu_ticks_enabled) {
    112         timers_state.cpu_ticks_offset -= cpu_get_host_ticks();
    113         timers_state.cpu_clock_offset -= get_clock();
    114         timers_state.cpu_ticks_enabled = 1;
    115     }
    116     seqlock_write_unlock(&timers_state.vm_clock_seqlock,
    117                        &timers_state.vm_clock_lock);
    118 }
    119 
    120 /*
    121  * disable cpu_get_ticks() : the clock is stopped. You must not call
    122  * cpu_get_ticks() after that.
    123  * Caller must hold BQL which serves as mutex for vm_clock_seqlock.
    124  */
    125 void cpu_disable_ticks(void)
    126 {
    127     seqlock_write_lock(&timers_state.vm_clock_seqlock,
    128                        &timers_state.vm_clock_lock);
    129     if (timers_state.cpu_ticks_enabled) {
    130         timers_state.cpu_ticks_offset += cpu_get_host_ticks();
    131         timers_state.cpu_clock_offset = cpu_get_clock_locked();
    132         timers_state.cpu_ticks_enabled = 0;
    133     }
    134     seqlock_write_unlock(&timers_state.vm_clock_seqlock,
    135                          &timers_state.vm_clock_lock);
    136 }
    137 
    138 static bool icount_state_needed(void *opaque)
    139 {
    140     return icount_enabled();
    141 }
    142 
    143 static bool warp_timer_state_needed(void *opaque)
    144 {
    145     TimersState *s = opaque;
    146     return s->icount_warp_timer != NULL;
    147 }
    148 
    149 static bool adjust_timers_state_needed(void *opaque)
    150 {
    151     TimersState *s = opaque;
    152     return s->icount_rt_timer != NULL;
    153 }
    154 
    155 static bool icount_shift_state_needed(void *opaque)
    156 {
    157     return icount_enabled() == 2;
    158 }
    159 
    160 /*
    161  * Subsection for warp timer migration is optional, because may not be created
    162  */
    163 static const VMStateDescription icount_vmstate_warp_timer = {
    164     .name = "timer/icount/warp_timer",
    165     .version_id = 1,
    166     .minimum_version_id = 1,
    167     .needed = warp_timer_state_needed,
    168     .fields = (VMStateField[]) {
    169         VMSTATE_INT64(vm_clock_warp_start, TimersState),
    170         VMSTATE_TIMER_PTR(icount_warp_timer, TimersState),
    171         VMSTATE_END_OF_LIST()
    172     }
    173 };
    174 
    175 static const VMStateDescription icount_vmstate_adjust_timers = {
    176     .name = "timer/icount/timers",
    177     .version_id = 1,
    178     .minimum_version_id = 1,
    179     .needed = adjust_timers_state_needed,
    180     .fields = (VMStateField[]) {
    181         VMSTATE_TIMER_PTR(icount_rt_timer, TimersState),
    182         VMSTATE_TIMER_PTR(icount_vm_timer, TimersState),
    183         VMSTATE_END_OF_LIST()
    184     }
    185 };
    186 
    187 static const VMStateDescription icount_vmstate_shift = {
    188     .name = "timer/icount/shift",
    189     .version_id = 2,
    190     .minimum_version_id = 2,
    191     .needed = icount_shift_state_needed,
    192     .fields = (VMStateField[]) {
    193         VMSTATE_INT16(icount_time_shift, TimersState),
    194         VMSTATE_INT64(last_delta, TimersState),
    195         VMSTATE_END_OF_LIST()
    196     }
    197 };
    198 
    199 /*
    200  * This is a subsection for icount migration.
    201  */
    202 static const VMStateDescription icount_vmstate_timers = {
    203     .name = "timer/icount",
    204     .version_id = 1,
    205     .minimum_version_id = 1,
    206     .needed = icount_state_needed,
    207     .fields = (VMStateField[]) {
    208         VMSTATE_INT64(qemu_icount_bias, TimersState),
    209         VMSTATE_INT64(qemu_icount, TimersState),
    210         VMSTATE_END_OF_LIST()
    211     },
    212     .subsections = (const VMStateDescription * []) {
    213         &icount_vmstate_warp_timer,
    214         &icount_vmstate_adjust_timers,
    215         &icount_vmstate_shift,
    216         NULL
    217     }
    218 };
    219 
    220 static const VMStateDescription vmstate_timers = {
    221     .name = "timer",
    222     .version_id = 2,
    223     .minimum_version_id = 1,
    224     .fields = (VMStateField[]) {
    225         VMSTATE_INT64(cpu_ticks_offset, TimersState),
    226         VMSTATE_UNUSED(8),
    227         VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
    228         VMSTATE_END_OF_LIST()
    229     },
    230     .subsections = (const VMStateDescription * []) {
    231         &icount_vmstate_timers,
    232         NULL
    233     }
    234 };
    235 
    236 static void do_nothing(CPUState *cpu, run_on_cpu_data unused)
    237 {
    238 }
    239 
    240 void qemu_timer_notify_cb(void *opaque, QEMUClockType type)
    241 {
    242     if (!icount_enabled() || type != QEMU_CLOCK_VIRTUAL) {
    243         qemu_notify_event();
    244         return;
    245     }
    246 
    247     if (qemu_in_vcpu_thread()) {
    248         /*
    249          * A CPU is currently running; kick it back out to the
    250          * tcg_cpu_exec() loop so it will recalculate its
    251          * icount deadline immediately.
    252          */
    253         qemu_cpu_kick(current_cpu);
    254     } else if (first_cpu) {
    255         /*
    256          * qemu_cpu_kick is not enough to kick a halted CPU out of
    257          * qemu_tcg_wait_io_event.  async_run_on_cpu, instead,
    258          * causes cpu_thread_is_idle to return false.  This way,
    259          * handle_icount_deadline can run.
    260          * If we have no CPUs at all for some reason, we don't
    261          * need to do anything.
    262          */
    263         async_run_on_cpu(first_cpu, do_nothing, RUN_ON_CPU_NULL);
    264     }
    265 }
    266 
    267 TimersState timers_state;
    268 
    269 /* initialize timers state and the cpu throttle for convenience */
    270 void cpu_timers_init(void)
    271 {
    272     seqlock_init(&timers_state.vm_clock_seqlock);
    273     qemu_spin_init(&timers_state.vm_clock_lock);
    274     vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
    275 
    276     cpu_throttle_init();
    277 }