[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 3/3] plat/kvm: Add KVM (x86_64) timer support
We are using TSC clock as main timer on KVM. Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx> --- plat/kvm/Makefile.uk | 3 + plat/kvm/clock_subr.c | 226 ++++++++++++++++++++++++ plat/kvm/include/kvm/clock_subr.h | 83 +++++++++ plat/kvm/include/kvm/tscclock.h | 42 +++++ plat/kvm/irq.c | 10 ++ plat/kvm/time.c | 62 +++++++ plat/kvm/tscclock.c | 356 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 782 insertions(+) create mode 100644 plat/kvm/clock_subr.c create mode 100644 plat/kvm/include/kvm/clock_subr.h create mode 100644 plat/kvm/include/kvm/tscclock.h create mode 100644 plat/kvm/time.c create mode 100644 plat/kvm/tscclock.c diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk index 46258ff..76c40f1 100644 --- a/plat/kvm/Makefile.uk +++ b/plat/kvm/Makefile.uk @@ -34,4 +34,7 @@ LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/intctrl.c LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/shutdown.c LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/memory.c LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/irq.c +LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/time.c +LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/tscclock.c +LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/clock_subr.c LIBKVMPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/lcpu.c|common diff --git a/plat/kvm/clock_subr.c b/plat/kvm/clock_subr.c new file mode 100644 index 0000000..6d7388b --- /dev/null +++ b/plat/kvm/clock_subr.c @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Martin Lucina + * Ricardo Koller + * Costin Lupu <costin.lupu@xxxxxxxxx> + * + * Copyright (c) 2015-2017 IBM + * Copyright (c) 2016-2017 Docker, Inc. + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Taken from solo5 clock_subr.c */ + +/* $NetBSD: clock_subr.c,v 1.26 2014/12/22 18:09:20 christos Exp $ */ + +/*- + * Copyright (c) 1996 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah $Hdr: clock.c 1.18 91/01/21$ + * + * @(#)clock.c 8.2 (Berkeley) 1/12/94 + */ + +#include <kvm/clock_subr.h> + +/* Some handy constants. */ +#define SECS_PER_MINUTE 60 +#define SECS_PER_HOUR 3600 +#define SECS_PER_DAY 86400 +#define DAYS_PER_COMMON_YEAR 365 +#define DAYS_PER_LEAP_YEAR 366 +#define SECS_PER_COMMON_YEAR (SECS_PER_DAY * DAYS_PER_COMMON_YEAR) +#define SECS_PER_LEAP_YEAR (SECS_PER_DAY * DAYS_PER_LEAP_YEAR) + +/* Traditional POSIX base year */ +#define POSIX_BASE_YEAR 1970 + +/* Some handy functions */ +static int days_in_month(int m) +{ + switch (m) { + case 2: + return 28; + case 4: case 6: case 9: case 11: + return 30; + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + return 31; + default: + return -1; + } +} + +/* + * This inline avoids some unnecessary modulo operations + * as compared with the usual macro: + * ( ((year % 4) == 0 && + * (year % 100) != 0) || + * ((year % 400) == 0) ) + * It is otherwise equivalent. + */ +static int is_leap_year(__u64 year) +{ + if ((year & 3) != 0) + return 0; + + if ((year % 100) != 0) + return 1; + + return (year % 400) == 0; +} + +static int days_per_year(__u64 year) +{ + return is_leap_year(year) ? DAYS_PER_LEAP_YEAR : DAYS_PER_COMMON_YEAR; +} + +/* + * Generic routines to convert between a POSIX date + * (seconds since 1/1/1970) and yr/mo/day/hr/min/sec + * Derived from arch/hp300/hp300/clock.c + */ + +#define FEBRUARY 2 + +/* for easier alignment: + * time from the epoch to 2000 (there were 7 leap years): + */ +#define DAYSTO2000 (365 * 30 + 7) + +/* 4 year intervals include 1 leap year */ +#define DAYS4YEARS (365 * 4 + 1) + +/* 100 year intervals include 24 leap years */ +#define DAYS100YEARS (365 * 100 + 24) + +/* 400 year intervals include 97 leap years */ +#define DAYS400YEARS (365 * 400 + 97) + +__u64 clock_ymdhms_to_secs(struct bmk_clock_ymdhms *dt) +{ + __u64 secs, i, year, days; + + year = dt->dt_year; + + /* + * Compute days since start of time + * First from years, then from months. + */ + if (year < POSIX_BASE_YEAR) + return 0; + + days = 0; + if (is_leap_year(year) && dt->dt_mon > FEBRUARY) + days++; + + if (year < 2000) { + /* simple way for early years */ + for (i = POSIX_BASE_YEAR; i < year; i++) + days += days_per_year(i); + + } else { + /* years are properly aligned */ + days += DAYSTO2000; + year -= 2000; + + i = year / 400; + days += i * DAYS400YEARS; + year -= i * 400; + + i = year / 100; + days += i * DAYS100YEARS; + year -= i * 100; + + i = year / 4; + days += i * DAYS4YEARS; + year -= i * 4; + + for (i = dt->dt_year - year; i < dt->dt_year; i++) + days += days_per_year(i); + } + + /* Months */ + for (i = 1; i < dt->dt_mon; i++) + days += days_in_month(i); + days += (dt->dt_day - 1); + + /* Add hours, minutes, seconds. */ + secs = (((__u64) days + * 24 + dt->dt_hour) + * 60 + dt->dt_min) + * 60 + dt->dt_sec; + + return secs; +} diff --git a/plat/kvm/include/kvm/clock_subr.h b/plat/kvm/include/kvm/clock_subr.h new file mode 100644 index 0000000..66f829b --- /dev/null +++ b/plat/kvm/include/kvm/clock_subr.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Martin Lucina + * Ricardo Koller + * Costin Lupu <costin.lupu@xxxxxxxxx> + * + * Copyright (c) 2015-2017 IBM + * Copyright (c) 2016-2017 Docker, Inc. + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Taken from solo5 clock_subr.h */ + +/*- + * Copyright (c) 1996 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _BMK_CLOCK_SUBR_H_ +#define _BMK_CLOCK_SUBR_H_ + +#include <uk/arch/types.h> + +/* + * "POSIX time" to/from "YY/MM/DD/hh/mm/ss" + */ +struct bmk_clock_ymdhms { + __u64 dt_year; + __u8 dt_mon; + __u8 dt_day; + __u8 dt_hour; + __u8 dt_min; + __u8 dt_sec; +}; + +__u64 clock_ymdhms_to_secs(struct bmk_clock_ymdhms *dt); + +/* + * BCD to binary. + */ +static inline unsigned int bcdtobin(unsigned int bcd) +{ + return ((bcd >> 4) & 0x0f) * 10 + (bcd & 0x0f); +} + +#endif /* _BMK_CLOCK_SUBR_H_ */ diff --git a/plat/kvm/include/kvm/tscclock.h b/plat/kvm/include/kvm/tscclock.h new file mode 100644 index 0000000..27d0e02 --- /dev/null +++ b/plat/kvm/include/kvm/tscclock.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Costin Lupu <costin.lupu@xxxxxxxxx> + * + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ + +#ifndef __KVM_TSCCLOCK_H__ +#define __KVM_TSCCLOCK_H__ + +int tscclock_init(void); +__u64 tscclock_monotonic(void); +__u64 tscclock_epochoffset(void); + +#endif /* __KVM_TSCCLOCK_H__ */ diff --git a/plat/kvm/irq.c b/plat/kvm/irq.c index 55f8e67..a3b2121 100644 --- a/plat/kvm/irq.c +++ b/plat/kvm/irq.c @@ -68,12 +68,22 @@ void irq_register(unsigned long irq, irq_handler_func_t func, void *arg) intctrl_clear_irq(irq); } +/* + * TODO This is a temporary solution used to identify non TSC clock + * interrupts in order to stop waiting for interrupts with deadline. + */ +extern long nontsc_interrupt_assert; + void irq_handle(unsigned long irq) { struct irq_handler *h; int handled = 0; UK_SLIST_FOREACH(h, &irq_handlers[irq], entries) { + /* TODO define platform wise macro for timer IRQ number */ + if (irq != 0) + nontsc_interrupt_assert = 1; + if (h->func(h->arg) == 1) { handled = 1; break; diff --git a/plat/kvm/time.c b/plat/kvm/time.c new file mode 100644 index 0000000..1276997 --- /dev/null +++ b/plat/kvm/time.c @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Dan Williams + * Martin Lucina + * Ricardo Koller + * Costin Lupu <costin.lupu@xxxxxxxxx> + * + * Copyright (c) 2015-2017 IBM + * Copyright (c) 2016-2017 Docker, Inc. + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Taken from solo5 time.c */ + +#include <stdlib.h> +#include <uk/plat/time.h> +#include <kvm/irq.h> +#include <kvm/tscclock.h> +#include <uk/assert.h> + + +/* return ns since time_init() */ +__nsec ukplat_monotonic_clock(void) +{ + return tscclock_monotonic(); +} + +/* return wall time in nsecs */ +__nsec ukplat_clock_wall(void) +{ + return tscclock_monotonic() + tscclock_epochoffset(); +} + +static int timer_handler(void *arg __unused) +{ + /* Yes, we handled the irq. */ + return 1; +} + +/* must be called before interrupts are enabled */ +void ukplat_time_init(void) +{ + int rc; + + irq_register(0, timer_handler, NULL); + + rc = tscclock_init(); + UK_ASSERT(rc == 0); +} diff --git a/plat/kvm/tscclock.c b/plat/kvm/tscclock.c new file mode 100644 index 0000000..1199f18 --- /dev/null +++ b/plat/kvm/tscclock.c @@ -0,0 +1,356 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Dan Williams + * Martin Lucina + * Ricardo Koller + * Costin Lupu <costin.lupu@xxxxxxxxx> + * + * Copyright (c) 2015-2017 IBM + * Copyright (c) 2016-2017 Docker, Inc. + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Taken from solo5 tscclock.c */ + +/*- + * Copyright (c) 2014, 2015 Antti Kantee. All Rights Reserved. + * Copyright (c) 2015 Martin Lucina. All Rights Reserved. + * Modified for solo5 by Ricardo Koller <kollerr@xxxxxxxxxx> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <uk/plat/lcpu.h> +#include <uk/plat/time.h> +#include <x86/cpu.h> +#include <kvm/clock_subr.h> +#include <uk/print.h> +#include <uk/assert.h> + +#define NSEC_PER_SEC 1000000000ULL + +#define TIMER_CNTR 0x40 +#define TIMER_MODE 0x43 +#define TIMER_SEL0 0x00 +#define TIMER_LATCH 0x00 +#define TIMER_RATEGEN 0x04 +#define TIMER_ONESHOT 0x08 +#define TIMER_16BIT 0x30 +#define TIMER_HZ 1193182 + +#define RTC_COMMAND 0x70 +#define RTC_DATA 0x71 +#define RTC_NMI_DISABLE (1<<8) +#define RTC_NMI_ENABLE 0 +#define RTC_SEC 0x00 +#define RTC_MIN 0x02 +#define RTC_HOUR 0x04 +#define RTC_DAY 0x07 +#define RTC_MONTH 0x08 +#define RTC_YEAR 0x09 +#define RTC_STATUS_A 0x0a +#define RTC_UIP (1<<7) + +/* RTC wall time offset at monotonic time base. */ +static __u64 rtc_epochoffset; + +/* + * TSC clock specific. + */ + +/* Base time values at the last call to tscclock_monotonic(). */ +static __u64 time_base; +static __u64 tsc_base; + +/* Multiplier for converting TSC ticks to nsecs. (0.32) fixed point. */ +static __u32 tsc_mult; + +/* + * Multiplier for converting nsecs to PIT ticks. (1.32) fixed point. + * + * Calculated as: + * + * f = NSEC_PER_SEC / TIMER_HZ (0.31) fixed point. + * pit_mult = 1 / f (1.32) fixed point. + */ +static const __u32 pit_mult = + (1ULL << 63) / ((NSEC_PER_SEC << 31) / TIMER_HZ); + + +/* + * Read the current i8254 channel 0 tick count. + */ +static unsigned int i8254_gettick(void) +{ + __u16 rdval; + + outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); + rdval = inb(TIMER_CNTR); + rdval |= (inb(TIMER_CNTR) << 8); + return rdval; +} + +/* + * Delay for approximately n microseconds using the i8254 channel 0 counter. + * Timer must be programmed appropriately before calling this function. + */ +static void i8254_delay(unsigned int n) +{ + unsigned int cur_tick, initial_tick; + int remaining; + const unsigned long timer_rval = TIMER_HZ / 100; + + initial_tick = i8254_gettick(); + + remaining = (unsigned long long) n * TIMER_HZ / 1000000; + + while (remaining > 1) { + cur_tick = i8254_gettick(); + if (cur_tick > initial_tick) + remaining -= timer_rval - (cur_tick - initial_tick); + else + remaining -= initial_tick - cur_tick; + initial_tick = cur_tick; + } +} + +/* + * Read a RTC register. Due to PC platform braindead-ness also disables NMI. + */ +static inline __u8 rtc_read(__u8 reg) +{ + outb(RTC_COMMAND, reg | RTC_NMI_DISABLE); + return inb(RTC_DATA); +} + +/* + * Return current RTC time. Note that due to waiting for the update cycle to + * complete, this call may take some time. + */ +static __u64 rtc_gettimeofday(void) +{ + struct bmk_clock_ymdhms dt; + unsigned long flags; + + flags = ukplat_lcpu_save_irqf(); + + /* + * If RTC_UIP is down, we have at least 244us to obtain a + * consistent reading before an update can occur. + */ + while (rtc_read(RTC_STATUS_A) & RTC_UIP) + continue; + + dt.dt_sec = bcdtobin(rtc_read(RTC_SEC)); + dt.dt_min = bcdtobin(rtc_read(RTC_MIN)); + dt.dt_hour = bcdtobin(rtc_read(RTC_HOUR)); + dt.dt_day = bcdtobin(rtc_read(RTC_DAY)); + dt.dt_mon = bcdtobin(rtc_read(RTC_MONTH)); + dt.dt_year = bcdtobin(rtc_read(RTC_YEAR)) + 2000; + + ukplat_lcpu_restore_irqf(flags); + + return ukarch_time_sec_to_nsec(clock_ymdhms_to_secs(&dt)); +} + +/* + * Beturn monotonic time using TSC clock. + */ +__u64 tscclock_monotonic(void) +{ + __u64 tsc_now, tsc_delta; + + /* + * Update time_base (monotonic time) and tsc_base (TSC time). + */ + tsc_now = rdtsc(); + tsc_delta = tsc_now - tsc_base; + time_base += mul64_32(tsc_delta, tsc_mult); + tsc_base = tsc_now; + + return time_base; +} + +/* + * Calibrate TSC and initialise TSC clock. + */ +int tscclock_init(void) +{ + __u64 tsc_freq, rtc_boot; + + /* Initialise i8254 timer channel 0 to mode 2 at 100 Hz */ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); + outb(TIMER_CNTR, (TIMER_HZ / 100) & 0xff); + outb(TIMER_CNTR, (TIMER_HZ / 100) >> 8); + + /* + * Read RTC "time at boot". This must be done just before tsc_base is + * initialised in order to get a correct offset below. + */ + rtc_boot = rtc_gettimeofday(); + + /* + * Calculate TSC frequency by calibrating against an 0.1s delay + * using the i8254 timer. + */ + tsc_base = rdtsc(); + i8254_delay(100000); + tsc_freq = (rdtsc() - tsc_base) * 10; + uk_printd(DLVL_INFO, + "Clock source: TSC, frequency estimate is %llu Hz\n", + (unsigned long long) tsc_freq); //TODO + + /* + * Calculate TSC scaling multiplier. + * + * (0.32) tsc_mult = NSEC_PER_SEC (32.32) / tsc_freq (32.0) + */ + tsc_mult = (NSEC_PER_SEC << 32) / tsc_freq; + + /* + * Monotonic time begins at tsc_base (first read of TSC before + * calibration). + */ + time_base = mul64_32(tsc_base, tsc_mult); + + /* + * Compute RTC epoch offset by subtracting monotonic time_base from RTC + * time at boot. + */ + rtc_epochoffset = rtc_boot - time_base; + + /* + * Initialise i8254 timer channel 0 to mode 4 (one shot). + */ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_ONESHOT | TIMER_16BIT); + + return 0; +} + +/* + * Return epoch offset (wall time offset to monotonic clock start). + */ +__u64 tscclock_epochoffset(void) +{ + return rtc_epochoffset; +} + +/* + * Minimum delta to sleep using PIT. Programming seems to have an overhead of + * 3-4us, but play it safe here. + */ +#define PIT_MIN_DELTA 16 + +/* + * Returns early if any interrupts are serviced, or if the requested delay is + * too short. Must be called with interrupts disabled, will enable interrupts + * "atomically" during idle loop. + */ +static void tscclock_cpu_block(__u64 until) +{ + __u64 now, delta_ns; + __u64 delta_ticks; + unsigned int ticks; + + UK_ASSERT(ukplat_lcpu_irqs_disabled()); + + now = ukplat_monotonic_clock(); + + /* + * Compute delta in PIT ticks. Return if it is less than minimum safe + * amount of ticks. Essentially this will cause us to spin until + * the timeout. + */ + delta_ns = until - now; + delta_ticks = mul64_32(delta_ns, pit_mult); + if (delta_ticks < PIT_MIN_DELTA) { + /* + * Since we are "spinning", quickly enable interrupts in + * the hopes that we might get new work and can do something + * else than spin. + */ + ukplat_lcpu_enable_irq(); + nop(); /* ints are enabled 1 instr after sti */ + ukplat_lcpu_disable_irq(); + return; + } + + /* + * Program the timer to interrupt the CPU after the delay has expired. + * Maximum timer delay is 65535 ticks. + */ + if (delta_ticks > 65535) + ticks = 65535; + else + ticks = delta_ticks; + + /* + * Note that according to the Intel 82C54 datasheet, p12 the + * interrupt is actually delivered in N + 1 ticks. + */ + ticks -= 1; + outb(TIMER_CNTR, ticks & 0xff); + outb(TIMER_CNTR, ticks >> 8); + + /* + * Wait for any interrupt. If we got an interrupt then + * just return into the scheduler which will check if there is + * work to do and send us back here if not. + * + * TODO: It would be more efficient for longer sleeps to be + * able to distinguish if the interrupt was the PIT interrupt + * and no other, but this will do for now. + */ + ukplat_lcpu_halt_irq(); +} + +long nontsc_interrupt_assert; + +void time_block_until(__snsec until) +{ + volatile long *pnontsc_interrupt_assert = &nontsc_interrupt_assert; + + while ((__snsec) ukplat_monotonic_clock() < until) { + tscclock_cpu_block(until); + + /* who triggered the interrupt? */ + if (*pnontsc_interrupt_assert) { + /* it was another device, stop blocking */ + nontsc_interrupt_assert = 0; + break; + } + /* it was us */ + } +} -- 2.1.4 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |