cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rtc_kern.c (4235B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2020 Intel Corporation
      4 * Author: Johannes Berg <johannes@sipsolutions.net>
      5 */
      6#include <linux/platform_device.h>
      7#include <linux/time-internal.h>
      8#include <linux/suspend.h>
      9#include <linux/err.h>
     10#include <linux/rtc.h>
     11#include <kern_util.h>
     12#include <irq_kern.h>
     13#include <os.h>
     14#include "rtc.h"
     15
     16static time64_t uml_rtc_alarm_time;
     17static bool uml_rtc_alarm_enabled;
     18static struct rtc_device *uml_rtc;
     19static int uml_rtc_irq_fd, uml_rtc_irq;
     20
     21#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
     22
     23static void uml_rtc_time_travel_alarm(struct time_travel_event *ev)
     24{
     25	uml_rtc_send_timetravel_alarm();
     26}
     27
     28static struct time_travel_event uml_rtc_alarm_event = {
     29	.fn = uml_rtc_time_travel_alarm,
     30};
     31#endif
     32
     33static int uml_rtc_read_time(struct device *dev, struct rtc_time *tm)
     34{
     35	struct timespec64 ts;
     36
     37	/* Use this to get correct time in time-travel mode */
     38	read_persistent_clock64(&ts);
     39	rtc_time64_to_tm(timespec64_to_ktime(ts) / NSEC_PER_SEC, tm);
     40
     41	return 0;
     42}
     43
     44static int uml_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
     45{
     46	rtc_time64_to_tm(uml_rtc_alarm_time, &alrm->time);
     47	alrm->enabled = uml_rtc_alarm_enabled;
     48
     49	return 0;
     50}
     51
     52static int uml_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
     53{
     54	unsigned long long secs;
     55
     56	if (!enable && !uml_rtc_alarm_enabled)
     57		return 0;
     58
     59	uml_rtc_alarm_enabled = enable;
     60
     61	secs = uml_rtc_alarm_time - ktime_get_real_seconds();
     62
     63	if (time_travel_mode == TT_MODE_OFF) {
     64		if (!enable) {
     65			uml_rtc_disable_alarm();
     66			return 0;
     67		}
     68
     69		/* enable or update */
     70		return uml_rtc_enable_alarm(secs);
     71	} else {
     72		time_travel_del_event(&uml_rtc_alarm_event);
     73
     74		if (enable)
     75			time_travel_add_event_rel(&uml_rtc_alarm_event,
     76						  secs * NSEC_PER_SEC);
     77	}
     78
     79	return 0;
     80}
     81
     82static int uml_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
     83{
     84	uml_rtc_alarm_irq_enable(dev, 0);
     85	uml_rtc_alarm_time = rtc_tm_to_time64(&alrm->time);
     86	uml_rtc_alarm_irq_enable(dev, alrm->enabled);
     87
     88	return 0;
     89}
     90
     91static const struct rtc_class_ops uml_rtc_ops = {
     92	.read_time = uml_rtc_read_time,
     93	.read_alarm = uml_rtc_read_alarm,
     94	.alarm_irq_enable = uml_rtc_alarm_irq_enable,
     95	.set_alarm = uml_rtc_set_alarm,
     96};
     97
     98static irqreturn_t uml_rtc_interrupt(int irq, void *data)
     99{
    100	unsigned long long c = 0;
    101
    102	/* alarm triggered, it's now off */
    103	uml_rtc_alarm_enabled = false;
    104
    105	os_read_file(uml_rtc_irq_fd, &c, sizeof(c));
    106	WARN_ON(c == 0);
    107
    108	pm_system_wakeup();
    109	rtc_update_irq(uml_rtc, 1, RTC_IRQF | RTC_AF);
    110
    111	return IRQ_HANDLED;
    112}
    113
    114static int uml_rtc_setup(void)
    115{
    116	int err;
    117
    118	err = uml_rtc_start(time_travel_mode != TT_MODE_OFF);
    119	if (WARN(err < 0, "err = %d\n", err))
    120		return err;
    121
    122	uml_rtc_irq_fd = err;
    123
    124	err = um_request_irq(UM_IRQ_ALLOC, uml_rtc_irq_fd, IRQ_READ,
    125			     uml_rtc_interrupt, 0, "rtc", NULL);
    126	if (err < 0) {
    127		uml_rtc_stop(time_travel_mode != TT_MODE_OFF);
    128		return err;
    129	}
    130
    131	irq_set_irq_wake(err, 1);
    132
    133	uml_rtc_irq = err;
    134	return 0;
    135}
    136
    137static void uml_rtc_cleanup(void)
    138{
    139	um_free_irq(uml_rtc_irq, NULL);
    140	uml_rtc_stop(time_travel_mode != TT_MODE_OFF);
    141}
    142
    143static int uml_rtc_probe(struct platform_device *pdev)
    144{
    145	int err;
    146
    147	err = uml_rtc_setup();
    148	if (err)
    149		return err;
    150
    151	uml_rtc = devm_rtc_allocate_device(&pdev->dev);
    152	if (IS_ERR(uml_rtc)) {
    153		err = PTR_ERR(uml_rtc);
    154		goto cleanup;
    155	}
    156
    157	uml_rtc->ops = &uml_rtc_ops;
    158
    159	device_init_wakeup(&pdev->dev, 1);
    160
    161	err = devm_rtc_register_device(uml_rtc);
    162	if (err)
    163		goto cleanup;
    164
    165	return 0;
    166cleanup:
    167	uml_rtc_cleanup();
    168	return err;
    169}
    170
    171static int uml_rtc_remove(struct platform_device *pdev)
    172{
    173	device_init_wakeup(&pdev->dev, 0);
    174	uml_rtc_cleanup();
    175	return 0;
    176}
    177
    178static struct platform_driver uml_rtc_driver = {
    179	.probe = uml_rtc_probe,
    180	.remove = uml_rtc_remove,
    181	.driver = {
    182		.name = "uml-rtc",
    183	},
    184};
    185
    186static int __init uml_rtc_init(void)
    187{
    188	struct platform_device *pdev;
    189	int err;
    190
    191	err = platform_driver_register(&uml_rtc_driver);
    192	if (err)
    193		return err;
    194
    195	pdev = platform_device_alloc("uml-rtc", 0);
    196	if (!pdev) {
    197		err = -ENOMEM;
    198		goto unregister;
    199	}
    200
    201	err = platform_device_add(pdev);
    202	if (err)
    203		goto unregister;
    204	return 0;
    205
    206unregister:
    207	platform_device_put(pdev);
    208	platform_driver_unregister(&uml_rtc_driver);
    209	return err;
    210}
    211device_initcall(uml_rtc_init);