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_ */