Files
Marc Zyngier 4123ca555b kvmtool: virtio: pass trapped vcpu to IO accessors
The recent introduction of bi-endianness on arm/arm64 had the
odd effect of breaking virtio-pci support on these platforms, as the
device endian field defaults to being VIRTIO_ENDIAN_HOST, which
is the wrong thing to have on a bi-endian capable architecture.

The fix is to check for the endianness on the ioport path the
same way we do it for mmio, which implies passing the vcpu all
the way down. Patch is a bit ugly, but aligns MMIO and ioport nicely.

Tested on arm64 and x86.

Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
2015-06-01 16:39:55 +01:00

156 lines
3.0 KiB
C

#include "kvm/rtc.h"
#include "kvm/ioport.h"
#include "kvm/kvm.h"
#include <time.h>
/*
* MC146818 RTC registers
*/
#define RTC_SECONDS 0x00
#define RTC_SECONDS_ALARM 0x01
#define RTC_MINUTES 0x02
#define RTC_MINUTES_ALARM 0x03
#define RTC_HOURS 0x04
#define RTC_HOURS_ALARM 0x05
#define RTC_DAY_OF_WEEK 0x06
#define RTC_DAY_OF_MONTH 0x07
#define RTC_MONTH 0x08
#define RTC_YEAR 0x09
#define RTC_CENTURY 0x32
#define RTC_REG_A 0x0A
#define RTC_REG_B 0x0B
#define RTC_REG_C 0x0C
#define RTC_REG_D 0x0D
struct rtc_device {
u8 cmos_idx;
u8 cmos_data[128];
};
static struct rtc_device rtc;
static inline unsigned char bin2bcd(unsigned val)
{
return ((val / 10) << 4) + val % 10;
}
static bool cmos_ram_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
struct tm *tm;
time_t ti;
time(&ti);
tm = gmtime(&ti);
switch (rtc.cmos_idx) {
case RTC_SECONDS:
ioport__write8(data, bin2bcd(tm->tm_sec));
break;
case RTC_MINUTES:
ioport__write8(data, bin2bcd(tm->tm_min));
break;
case RTC_HOURS:
ioport__write8(data, bin2bcd(tm->tm_hour));
break;
case RTC_DAY_OF_WEEK:
ioport__write8(data, bin2bcd(tm->tm_wday + 1));
break;
case RTC_DAY_OF_MONTH:
ioport__write8(data, bin2bcd(tm->tm_mday));
break;
case RTC_MONTH:
ioport__write8(data, bin2bcd(tm->tm_mon + 1));
break;
case RTC_YEAR: {
int year;
year = tm->tm_year + 1900;
ioport__write8(data, bin2bcd(year % 100));
break;
}
case RTC_CENTURY: {
int year;
year = tm->tm_year + 1900;
ioport__write8(data, bin2bcd(year / 100));
break;
}
default:
ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]);
break;
}
return true;
}
static bool cmos_ram_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
switch (rtc.cmos_idx) {
case RTC_REG_C:
case RTC_REG_D:
/* Read-only */
break;
default:
rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
break;
}
return true;
}
static struct ioport_operations cmos_ram_data_ioport_ops = {
.io_out = cmos_ram_data_out,
.io_in = cmos_ram_data_in,
};
static bool cmos_ram_index_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
u8 value = ioport__read8(data);
vcpu->kvm->nmi_disabled = value & (1UL << 7);
rtc.cmos_idx = value & ~(1UL << 7);
return true;
}
static struct ioport_operations cmos_ram_index_ioport_ops = {
.io_out = cmos_ram_index_out,
};
int rtc__init(struct kvm *kvm)
{
int r = 0;
/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
r = ioport__register(kvm, 0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
if (r < 0)
return r;
r = ioport__register(kvm, 0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
if (r < 0) {
ioport__unregister(kvm, 0x0071);
return r;
}
return r;
}
dev_init(rtc__init);
int rtc__exit(struct kvm *kvm)
{
/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
ioport__unregister(kvm, 0x0070);
ioport__unregister(kvm, 0x0071);
return 0;
}
dev_exit(rtc__exit);