cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

rtc.c (5934B)


      1/*
      2 * RTC configuration and clock read
      3 *
      4 * Copyright (c) 2003-2020 QEMU contributors
      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-common.h"
     27#include "qemu/cutils.h"
     28#include "qapi/error.h"
     29#include "qapi/qmp/qerror.h"
     30#include "qemu/error-report.h"
     31#include "qemu/option.h"
     32#include "qemu/timer.h"
     33#include "qom/object.h"
     34#include "sysemu/replay.h"
     35#include "sysemu/sysemu.h"
     36
     37static enum {
     38    RTC_BASE_UTC,
     39    RTC_BASE_LOCALTIME,
     40    RTC_BASE_DATETIME,
     41} rtc_base_type = RTC_BASE_UTC;
     42static time_t rtc_ref_start_datetime;
     43static int rtc_realtime_clock_offset; /* used only with QEMU_CLOCK_REALTIME */
     44static int rtc_host_datetime_offset = -1; /* valid & used only with
     45                                             RTC_BASE_DATETIME */
     46QEMUClockType rtc_clock;
     47/***********************************************************/
     48/* RTC reference time/date access */
     49static time_t qemu_ref_timedate(QEMUClockType clock)
     50{
     51    time_t value = qemu_clock_get_ms(clock) / 1000;
     52    switch (clock) {
     53    case QEMU_CLOCK_REALTIME:
     54        value -= rtc_realtime_clock_offset;
     55        /* fall through */
     56    case QEMU_CLOCK_VIRTUAL:
     57        value += rtc_ref_start_datetime;
     58        break;
     59    case QEMU_CLOCK_HOST:
     60        if (rtc_base_type == RTC_BASE_DATETIME) {
     61            value -= rtc_host_datetime_offset;
     62        }
     63        break;
     64    default:
     65        assert(0);
     66    }
     67    return value;
     68}
     69
     70void qemu_get_timedate(struct tm *tm, int offset)
     71{
     72    time_t ti = qemu_ref_timedate(rtc_clock);
     73
     74    ti += offset;
     75
     76    switch (rtc_base_type) {
     77    case RTC_BASE_DATETIME:
     78    case RTC_BASE_UTC:
     79        gmtime_r(&ti, tm);
     80        break;
     81    case RTC_BASE_LOCALTIME:
     82        localtime_r(&ti, tm);
     83        break;
     84    }
     85}
     86
     87int qemu_timedate_diff(struct tm *tm)
     88{
     89    time_t seconds;
     90
     91    switch (rtc_base_type) {
     92    case RTC_BASE_DATETIME:
     93    case RTC_BASE_UTC:
     94        seconds = mktimegm(tm);
     95        break;
     96    case RTC_BASE_LOCALTIME:
     97    {
     98        struct tm tmp = *tm;
     99        tmp.tm_isdst = -1; /* use timezone to figure it out */
    100        seconds = mktime(&tmp);
    101        break;
    102    }
    103    default:
    104        abort();
    105    }
    106
    107    return seconds - qemu_ref_timedate(QEMU_CLOCK_HOST);
    108}
    109
    110static void configure_rtc_base_datetime(const char *startdate)
    111{
    112    time_t rtc_start_datetime;
    113    struct tm tm;
    114
    115    if (sscanf(startdate, "%d-%d-%dT%d:%d:%d", &tm.tm_year, &tm.tm_mon,
    116               &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) {
    117        /* OK */
    118    } else if (sscanf(startdate, "%d-%d-%d",
    119                      &tm.tm_year, &tm.tm_mon, &tm.tm_mday) == 3) {
    120        tm.tm_hour = 0;
    121        tm.tm_min = 0;
    122        tm.tm_sec = 0;
    123    } else {
    124        goto date_fail;
    125    }
    126    tm.tm_year -= 1900;
    127    tm.tm_mon--;
    128    rtc_start_datetime = mktimegm(&tm);
    129    if (rtc_start_datetime == -1) {
    130    date_fail:
    131        error_report("invalid datetime format");
    132        error_printf("valid formats: "
    133                     "'2006-06-17T16:01:21' or '2006-06-17'\n");
    134        exit(1);
    135    }
    136    rtc_host_datetime_offset = rtc_ref_start_datetime - rtc_start_datetime;
    137    rtc_ref_start_datetime = rtc_start_datetime;
    138}
    139
    140void configure_rtc(QemuOpts *opts)
    141{
    142    const char *value;
    143
    144    /* Set defaults */
    145    rtc_clock = QEMU_CLOCK_HOST;
    146    rtc_ref_start_datetime = qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000;
    147    rtc_realtime_clock_offset = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000;
    148
    149    value = qemu_opt_get(opts, "base");
    150    if (value) {
    151        if (!strcmp(value, "utc")) {
    152            rtc_base_type = RTC_BASE_UTC;
    153        } else if (!strcmp(value, "localtime")) {
    154            Error *blocker = NULL;
    155            rtc_base_type = RTC_BASE_LOCALTIME;
    156            error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED,
    157                      "-rtc base=localtime");
    158            replay_add_blocker(blocker);
    159        } else {
    160            rtc_base_type = RTC_BASE_DATETIME;
    161            configure_rtc_base_datetime(value);
    162        }
    163    }
    164    value = qemu_opt_get(opts, "clock");
    165    if (value) {
    166        if (!strcmp(value, "host")) {
    167            rtc_clock = QEMU_CLOCK_HOST;
    168        } else if (!strcmp(value, "rt")) {
    169            rtc_clock = QEMU_CLOCK_REALTIME;
    170        } else if (!strcmp(value, "vm")) {
    171            rtc_clock = QEMU_CLOCK_VIRTUAL;
    172        } else {
    173            error_report("invalid option value '%s'", value);
    174            exit(1);
    175        }
    176    }
    177    value = qemu_opt_get(opts, "driftfix");
    178    if (value) {
    179        if (!strcmp(value, "slew")) {
    180            object_register_sugar_prop("mc146818rtc",
    181                                       "lost_tick_policy",
    182                                       "slew",
    183                                       false);
    184        } else if (!strcmp(value, "none")) {
    185            /* discard is default */
    186        } else {
    187            error_report("invalid option value '%s'", value);
    188            exit(1);
    189        }
    190    }
    191}