From 022ef92b627c394aa00ccb26c747c833f76dffac Mon Sep 17 00:00:00 2001 From: Sainath Grandhi Date: Tue, 14 Aug 2018 22:21:11 -0700 Subject: [PATCH] hv: Add vrtc emulation support for ACRN partition mode This patch adds code to support read-only RTC support for guests run by partition mode ACRN. It supports RW for CMOS address port 0x70 and RO for CMOS data port 0x71. Reads to CMOS RAM offsets are fetched by reading CMOS h/w directly and writes to CMOS offsets are discarded. Signed-off-by: Sainath Grandhi --- hypervisor/Makefile | 1 + hypervisor/arch/x86/guest/vm.c | 2 +- hypervisor/dm/vrtc.c | 86 ++++++++++++++++++++++++++ hypervisor/include/arch/x86/guest/vm.h | 3 + 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 hypervisor/dm/vrtc.c diff --git a/hypervisor/Makefile b/hypervisor/Makefile index d3e14f760..e30221321 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -177,6 +177,7 @@ C_SRCS += dm/vioapic.c ifeq ($(CONFIG_PARTITION_MODE),y) C_SRCS += $(wildcard dm/vpci/*.c) C_SRCS += $(wildcard partition/*.c) +C_SRCS += dm/vrtc.c endif C_SRCS += bsp/$(CONFIG_PLATFORM)/vm_description.c diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index f2efbf9e7..b16624d46 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -205,7 +205,7 @@ int create_vm(struct vm_description *vm_desc, struct vm **rtn_vm) if (vm_desc->vm_vuart) { vm->vuart = vuart_init(vm); } - + vrtc_init(vm); vpci_init(vm); #endif diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c new file mode 100644 index 000000000..9f9be40bb --- /dev/null +++ b/hypervisor/dm/vrtc.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#define CMOS_ADDR_PORT 0x70U +#define CMOS_DATA_PORT 0x71U + +#define RTC_STATUSA 0x0AU /* status register A */ +#define RTCSA_TUP 0x80U /* time update, don't look now */ + +static spinlock_t cmos_lock = { .head = 0U, .tail = 0U }; + +static uint8_t cmos_read(uint8_t addr) +{ + pio_write8(addr, CMOS_ADDR_PORT); + return pio_read8(CMOS_DATA_PORT); +} + +static bool cmos_update_in_progress(void) +{ + return (cmos_read(RTC_STATUSA) & RTCSA_TUP)?1:0; +} + +static uint8_t cmos_get_reg_val(uint8_t addr) +{ + uint8_t reg; + int tries = 2000U; + + spinlock_obtain(&cmos_lock); + + /* Make sure an update isn't in progress */ + while (cmos_update_in_progress() && tries--) + ; + + reg = cmos_read(addr); + + spinlock_release(&cmos_lock); + return reg; +} + +static uint32_t vrtc_read(__unused struct vm_io_handler *hdlr, struct vm *vm, + uint16_t addr, __unused size_t width) +{ + uint8_t reg; + uint8_t offset; + + offset = vm->vrtc_offset; + + if (addr == CMOS_ADDR_PORT) { + return vm->vrtc_offset; + } + + reg = cmos_get_reg_val(offset); + return reg; +} + +static void vrtc_write(__unused struct vm_io_handler *hdlr, struct vm *vm, uint16_t addr, + size_t width, uint32_t value) +{ + + if (width != 1U) + return; + + if (addr == CMOS_ADDR_PORT) { + vm->vrtc_offset = value & 0x7FU; + } +} + +void vrtc_init(struct vm *vm) +{ + struct vm_io_range range = { + .flags = IO_ATTR_RW, .base = CMOS_ADDR_PORT, .len = 2U}; + + /* Initializing the CMOS RAM offset to 0U */ + vm->vrtc_offset = 0U; + + register_io_emulation_handler(vm, &range, vrtc_read, vrtc_write); +} diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 800ab4df0..6822c1f41 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -166,6 +166,7 @@ struct vm { #ifdef CONFIG_PARTITION_MODE struct vm_description *vm_desc; struct vpci vpci; + uint8_t vrtc_offset; #endif }; @@ -275,5 +276,7 @@ struct pcpu_vm_desc_mapping { bool is_bsp; }; extern const struct pcpu_vm_desc_mapping pcpu_vm_desc_map[]; + +void vrtc_init(struct vm *vm); #endif #endif /* VM_H_ */