qemu/hw/rtc/goldfish_rtc.c
<<
>>
Prefs
   1/*
   2 * Goldfish virtual platform RTC
   3 *
   4 * Copyright (C) 2019 Western Digital Corporation or its affiliates.
   5 *
   6 * For more details on Google Goldfish virtual platform refer:
   7 * https://android.googlesource.com/platform/external/qemu/+/refs/heads/emu-2.0-release/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
   8 *
   9 * This program is free software; you can redistribute it and/or modify it
  10 * under the terms and conditions of the GNU General Public License,
  11 * version 2 or later, as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope it will be useful, but WITHOUT
  14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  16 * more details.
  17 *
  18 * You should have received a copy of the GNU General Public License along with
  19 * this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "hw/rtc/goldfish_rtc.h"
  24#include "migration/vmstate.h"
  25#include "hw/irq.h"
  26#include "hw/qdev-properties.h"
  27#include "hw/sysbus.h"
  28#include "qemu/bitops.h"
  29#include "qemu/timer.h"
  30#include "sysemu/sysemu.h"
  31#include "sysemu/rtc.h"
  32#include "qemu/cutils.h"
  33#include "qemu/log.h"
  34
  35#include "trace.h"
  36
  37#define RTC_TIME_LOW            0x00
  38#define RTC_TIME_HIGH           0x04
  39#define RTC_ALARM_LOW           0x08
  40#define RTC_ALARM_HIGH          0x0c
  41#define RTC_IRQ_ENABLED         0x10
  42#define RTC_CLEAR_ALARM         0x14
  43#define RTC_ALARM_STATUS        0x18
  44#define RTC_CLEAR_INTERRUPT     0x1c
  45
  46static void goldfish_rtc_update(GoldfishRTCState *s)
  47{
  48    qemu_set_irq(s->irq, (s->irq_pending & s->irq_enabled) ? 1 : 0);
  49}
  50
  51static void goldfish_rtc_interrupt(void *opaque)
  52{
  53    GoldfishRTCState *s = (GoldfishRTCState *)opaque;
  54
  55    s->alarm_running = 0;
  56    s->irq_pending = 1;
  57    goldfish_rtc_update(s);
  58}
  59
  60static uint64_t goldfish_rtc_get_count(GoldfishRTCState *s)
  61{
  62    return s->tick_offset + (uint64_t)qemu_clock_get_ns(rtc_clock);
  63}
  64
  65static void goldfish_rtc_clear_alarm(GoldfishRTCState *s)
  66{
  67    timer_del(s->timer);
  68    s->alarm_running = 0;
  69}
  70
  71static void goldfish_rtc_set_alarm(GoldfishRTCState *s)
  72{
  73    uint64_t ticks = goldfish_rtc_get_count(s);
  74    uint64_t event = s->alarm_next;
  75
  76    if (event <= ticks) {
  77        goldfish_rtc_clear_alarm(s);
  78        goldfish_rtc_interrupt(s);
  79    } else {
  80        /*
  81         * We should be setting timer expiry to:
  82         *     qemu_clock_get_ns(rtc_clock) + (event - ticks)
  83         * but this is equivalent to:
  84         *     event - s->tick_offset
  85         */
  86        timer_mod(s->timer, event - s->tick_offset);
  87        s->alarm_running = 1;
  88    }
  89}
  90
  91static uint64_t goldfish_rtc_read(void *opaque, hwaddr offset,
  92                                  unsigned size)
  93{
  94    GoldfishRTCState *s = opaque;
  95    uint64_t r = 0;
  96
  97    /*
  98     * From the documentation linked at the top of the file:
  99     *
 100     *   To read the value, the kernel must perform an IO_READ(TIME_LOW), which
 101     *   returns an unsigned 32-bit value, before an IO_READ(TIME_HIGH), which
 102     *   returns a signed 32-bit value, corresponding to the higher half of the
 103     *   full value.
 104     */
 105    switch (offset) {
 106    case RTC_TIME_LOW:
 107        r = goldfish_rtc_get_count(s);
 108        s->time_high = r >> 32;
 109        r &= 0xffffffff;
 110        break;
 111    case RTC_TIME_HIGH:
 112        r = s->time_high;
 113        break;
 114    case RTC_ALARM_LOW:
 115        r = s->alarm_next & 0xffffffff;
 116        break;
 117    case RTC_ALARM_HIGH:
 118        r = s->alarm_next >> 32;
 119        break;
 120    case RTC_IRQ_ENABLED:
 121        r = s->irq_enabled;
 122        break;
 123    case RTC_ALARM_STATUS:
 124        r = s->alarm_running;
 125        break;
 126    default:
 127        qemu_log_mask(LOG_GUEST_ERROR,
 128                  "%s: offset 0x%x is UNIMP.\n", __func__, (uint32_t)offset);
 129        break;
 130    }
 131
 132    trace_goldfish_rtc_read(offset, r);
 133
 134    return r;
 135}
 136
 137static void goldfish_rtc_write(void *opaque, hwaddr offset,
 138                               uint64_t value, unsigned size)
 139{
 140    GoldfishRTCState *s = opaque;
 141    uint64_t current_tick, new_tick;
 142
 143    switch (offset) {
 144    case RTC_TIME_LOW:
 145        current_tick = goldfish_rtc_get_count(s);
 146        new_tick = deposit64(current_tick, 0, 32, value);
 147        s->tick_offset += new_tick - current_tick;
 148        break;
 149    case RTC_TIME_HIGH:
 150        current_tick = goldfish_rtc_get_count(s);
 151        new_tick = deposit64(current_tick, 32, 32, value);
 152        s->tick_offset += new_tick - current_tick;
 153        break;
 154    case RTC_ALARM_LOW:
 155        s->alarm_next = deposit64(s->alarm_next, 0, 32, value);
 156        goldfish_rtc_set_alarm(s);
 157        break;
 158    case RTC_ALARM_HIGH:
 159        s->alarm_next = deposit64(s->alarm_next, 32, 32, value);
 160        break;
 161    case RTC_IRQ_ENABLED:
 162        s->irq_enabled = (uint32_t)(value & 0x1);
 163        goldfish_rtc_update(s);
 164        break;
 165    case RTC_CLEAR_ALARM:
 166        goldfish_rtc_clear_alarm(s);
 167        break;
 168    case RTC_CLEAR_INTERRUPT:
 169        s->irq_pending = 0;
 170        goldfish_rtc_update(s);
 171        break;
 172    default:
 173        qemu_log_mask(LOG_GUEST_ERROR,
 174                  "%s: offset 0x%x is UNIMP.\n", __func__, (uint32_t)offset);
 175        break;
 176    }
 177
 178    trace_goldfish_rtc_write(offset, value);
 179}
 180
 181static int goldfish_rtc_pre_save(void *opaque)
 182{
 183    uint64_t delta;
 184    GoldfishRTCState *s = opaque;
 185
 186    /*
 187     * We want to migrate this offset, which sounds straightforward.
 188     * Unfortunately, we cannot directly pass tick_offset because
 189     * rtc_clock on destination Host might not be same source Host.
 190     *
 191     * To tackle, this we pass tick_offset relative to vm_clock from
 192     * source Host and make it relative to rtc_clock at destination Host.
 193     */
 194    delta = qemu_clock_get_ns(rtc_clock) -
 195            qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 196    s->tick_offset_vmstate = s->tick_offset + delta;
 197
 198    return 0;
 199}
 200
 201static int goldfish_rtc_post_load(void *opaque, int version_id)
 202{
 203    uint64_t delta;
 204    GoldfishRTCState *s = opaque;
 205
 206    /*
 207     * We extract tick_offset from tick_offset_vmstate by doing
 208     * reverse math compared to pre_save() function.
 209     */
 210    delta = qemu_clock_get_ns(rtc_clock) -
 211            qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 212    s->tick_offset = s->tick_offset_vmstate - delta;
 213
 214    goldfish_rtc_set_alarm(s);
 215
 216    return 0;
 217}
 218
 219static const MemoryRegionOps goldfish_rtc_ops[2] = {
 220    [false] = {
 221        .read = goldfish_rtc_read,
 222        .write = goldfish_rtc_write,
 223        .endianness = DEVICE_LITTLE_ENDIAN,
 224        .valid = {
 225            .min_access_size = 4,
 226            .max_access_size = 4
 227        }
 228    },
 229    [true] = {
 230        .read = goldfish_rtc_read,
 231        .write = goldfish_rtc_write,
 232        .endianness = DEVICE_BIG_ENDIAN,
 233        .valid = {
 234            .min_access_size = 4,
 235            .max_access_size = 4
 236        }
 237    },
 238};
 239
 240static const VMStateDescription goldfish_rtc_vmstate = {
 241    .name = TYPE_GOLDFISH_RTC,
 242    .version_id = 2,
 243    .pre_save = goldfish_rtc_pre_save,
 244    .post_load = goldfish_rtc_post_load,
 245    .fields = (VMStateField[]) {
 246        VMSTATE_UINT64(tick_offset_vmstate, GoldfishRTCState),
 247        VMSTATE_UINT64(alarm_next, GoldfishRTCState),
 248        VMSTATE_UINT32(alarm_running, GoldfishRTCState),
 249        VMSTATE_UINT32(irq_pending, GoldfishRTCState),
 250        VMSTATE_UINT32(irq_enabled, GoldfishRTCState),
 251        VMSTATE_UINT32(time_high, GoldfishRTCState),
 252        VMSTATE_END_OF_LIST()
 253    }
 254};
 255
 256static void goldfish_rtc_reset(DeviceState *dev)
 257{
 258    GoldfishRTCState *s = GOLDFISH_RTC(dev);
 259    struct tm tm;
 260
 261    timer_del(s->timer);
 262
 263    qemu_get_timedate(&tm, 0);
 264    s->tick_offset = mktimegm(&tm);
 265    s->tick_offset *= NANOSECONDS_PER_SECOND;
 266    s->tick_offset -= qemu_clock_get_ns(rtc_clock);
 267    s->tick_offset_vmstate = 0;
 268    s->alarm_next = 0;
 269    s->alarm_running = 0;
 270    s->irq_pending = 0;
 271    s->irq_enabled = 0;
 272}
 273
 274static void goldfish_rtc_realize(DeviceState *d, Error **errp)
 275{
 276    SysBusDevice *dev = SYS_BUS_DEVICE(d);
 277    GoldfishRTCState *s = GOLDFISH_RTC(d);
 278
 279    memory_region_init_io(&s->iomem, OBJECT(s),
 280                          &goldfish_rtc_ops[s->big_endian], s,
 281                          "goldfish_rtc", 0x24);
 282    sysbus_init_mmio(dev, &s->iomem);
 283
 284    sysbus_init_irq(dev, &s->irq);
 285
 286    s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s);
 287}
 288
 289static Property goldfish_rtc_properties[] = {
 290    DEFINE_PROP_BOOL("big-endian", GoldfishRTCState, big_endian,
 291                      false),
 292    DEFINE_PROP_END_OF_LIST(),
 293};
 294
 295static void goldfish_rtc_class_init(ObjectClass *klass, void *data)
 296{
 297    DeviceClass *dc = DEVICE_CLASS(klass);
 298
 299    device_class_set_props(dc, goldfish_rtc_properties);
 300    dc->realize = goldfish_rtc_realize;
 301    dc->reset = goldfish_rtc_reset;
 302    dc->vmsd = &goldfish_rtc_vmstate;
 303}
 304
 305static const TypeInfo goldfish_rtc_info = {
 306    .name          = TYPE_GOLDFISH_RTC,
 307    .parent        = TYPE_SYS_BUS_DEVICE,
 308    .instance_size = sizeof(GoldfishRTCState),
 309    .class_init    = goldfish_rtc_class_init,
 310};
 311
 312static void goldfish_rtc_register_types(void)
 313{
 314    type_register_static(&goldfish_rtc_info);
 315}
 316
 317type_init(goldfish_rtc_register_types)
 318