2019-11-06 12:56:36 +01:00
|
|
|
/*
|
|
|
|
* Goldfish virtual platform RTC
|
|
|
|
*
|
|
|
|
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
|
|
|
|
*
|
|
|
|
* For more details on Google Goldfish virtual platform refer:
|
|
|
|
* https://android.googlesource.com/platform/external/qemu/+/master/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
|
|
* version 2 or later, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef HW_RTC_GOLDFISH_RTC_H
|
|
|
|
#define HW_RTC_GOLDFISH_RTC_H
|
|
|
|
|
|
|
|
#include "hw/sysbus.h"
|
2020-09-03 22:43:22 +02:00
|
|
|
#include "qom/object.h"
|
2019-11-06 12:56:36 +01:00
|
|
|
|
|
|
|
#define TYPE_GOLDFISH_RTC "goldfish_rtc"
|
2020-09-16 20:25:19 +02:00
|
|
|
OBJECT_DECLARE_SIMPLE_TYPE(GoldfishRTCState, GOLDFISH_RTC)
|
2019-11-06 12:56:36 +01:00
|
|
|
|
2020-09-03 22:43:22 +02:00
|
|
|
struct GoldfishRTCState {
|
2019-11-06 12:56:36 +01:00
|
|
|
SysBusDevice parent_obj;
|
|
|
|
|
|
|
|
MemoryRegion iomem;
|
|
|
|
QEMUTimer *timer;
|
|
|
|
qemu_irq irq;
|
|
|
|
|
|
|
|
uint64_t tick_offset;
|
|
|
|
uint64_t tick_offset_vmstate;
|
|
|
|
uint64_t alarm_next;
|
|
|
|
uint32_t alarm_running;
|
|
|
|
uint32_t irq_pending;
|
|
|
|
uint32_t irq_enabled;
|
goldfish_rtc: Fix non-atomic read behaviour of TIME_LOW/TIME_HIGH
The specification says:
0x00 TIME_LOW R: Get current time, then return low-order 32-bits.
0x04 TIME_HIGH R: Return high 32-bits from previous TIME_LOW read.
...
To read the value, the kernel must perform an IO_READ(TIME_LOW),
which returns an unsigned 32-bit value, before an IO_READ(TIME_HIGH),
which returns a signed 32-bit value, corresponding to the higher half
of the full value.
However, we were just returning the current time for both. If the guest
is unlucky enough to read TIME_LOW and TIME_HIGH either side of an
overflow of the lower half, it will see time be in the future, before
jumping backwards on the next read, and Linux currently relies on the
atomicity guaranteed by the spec so is affected by this. Fix this
violation of the spec by caching the correct value for TIME_HIGH
whenever TIME_LOW is read, and returning that value for any TIME_HIGH
read.
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20200718004934.83174-1-jrtc27@jrtc27.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2020-07-18 02:49:34 +02:00
|
|
|
uint32_t time_high;
|
2022-06-12 13:53:44 +02:00
|
|
|
|
|
|
|
bool big_endian;
|
2020-09-03 22:43:22 +02:00
|
|
|
};
|
2019-11-06 12:56:36 +01:00
|
|
|
|
|
|
|
#endif
|