lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1387439515-8926-8-git-send-email-jlee@suse.com>
Date:	Thu, 19 Dec 2013 15:51:48 +0800
From:	"Lee, Chun-Yi" <joeyli.kernel@...il.com>
To:	"Rafael J. Wysocki" <rjw@...ysocki.net>,
	Alessandro Zummo <a.zummo@...ertech.it>,
	"H. Peter Anvin" <hpa@...or.com>,
	Matt Fleming <matt@...sole-pimps.org>,
	Matthew Garrett <matthew.garrett@...ula.com>
Cc:	Elliott@...com, samer.el-haj-mahmoud@...com,
	Oliver Neukum <oneukum@...e.de>, werner@...e.com,
	trenn@...e.de, JBeulich@...e.com, linux-kernel@...r.kernel.org,
	rtc-linux@...glegroups.com, x86@...nel.org,
	"linux-efi@...r.kernel.org" <linux-efi@...r.kernel.org>,
	linux-acpi@...r.kernel.org, "Lee, Chun-Yi" <jlee@...e.com>
Subject: [RFC PATCH 07/14] rtc-efi: add GMTOFF support to rtc_efi

Per UEFI 2.3.1 spec, we can use SetTime() to store the timezone value to
BIOS and get it back by GetTime(). It's good for installation system to
gain the default timezone setting from BIOS that was set by
manufacturer.

This patch adds 2 new iotrl: RTC_RD_GMTOFF and RTC_SET_GMTOFF to rtc_efi
support get/set gmt offset that mapping to the GUN's tm_gmtoff extension
(Seconds east of UTC).
Due the timezone definition of UEFI is "Localtime = UTC - TimeZone",
rtc_efi driver will transfer the format between GNU and EFI.

The logic of timezone only affect on x86 architecture and keep the
original EFI_UNSPECIFIED_TIMEZONE value on IA64.

Signed-off-by: Lee, Chun-Yi <jlee@...e.com>
---
 drivers/rtc/rtc-efi.c |  100 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 99 insertions(+), 1 deletions(-)

diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index c4c3843..e0e3c7e 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -75,7 +75,10 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
 	eft->second	= wtime->tm_sec;
 	eft->nanosecond = 0;
 	eft->daylight	= wtime->tm_isdst ? EFI_ISDST : 0;
+#ifdef CONFIG_IA64
+	/* avoid overwrite timezone on non-IA64 platform. e.g. x86_64 */
 	eft->timezone	= EFI_UNSPECIFIED_TIMEZONE;
+#endif
 }
 
 static void
@@ -108,6 +111,84 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
 	}
 }
 
+static int efi_read_gmtoff(struct device *dev, long int *arg)
+{
+	efi_status_t status;
+	efi_time_t eft;
+	efi_time_cap_t cap;
+	s16 timezone;
+
+	status = efi.get_time(&eft, &cap);
+
+	if (status != EFI_SUCCESS) {
+		/* should never happen */
+		pr_err("efitime: can't read time\n");
+		return -EINVAL;
+	}
+
+	timezone = (s16)le16_to_cpu(eft.timezone);
+	*arg = EFI_UNSPECIFIED_TIMEZONE * 60;
+	if (abs(timezone) != EFI_UNSPECIFIED_TIMEZONE &&
+	    abs(timezone) <= 1440)
+		*arg = timezone * 60 * -1;
+
+	return 0;
+}
+
+static int efi_set_gmtoff(struct device *dev, long int arg)
+{
+	efi_status_t status;
+	efi_time_t eft;
+	efi_time_cap_t cap;
+	s16 timezone;
+
+	/* transfer seconds east of UTC to minutes for ACPI */
+	timezone = arg / 60 * -1;
+	if (abs(timezone) > 1440 &&
+	    abs(timezone) != EFI_UNSPECIFIED_TIMEZONE)
+		return -EINVAL;
+
+	/* can not use -2047 */
+	if (timezone == EFI_UNSPECIFIED_TIMEZONE * -1)
+		timezone = EFI_UNSPECIFIED_TIMEZONE;
+
+	status = efi.get_time(&eft, &cap);
+
+	if (status != EFI_SUCCESS) {
+		pr_err("efitime: can't read time\n");
+		return -EINVAL;
+	}
+
+	eft.timezone = (s16)cpu_to_le16(timezone);
+	status = efi.set_time(&eft);
+	if (status != EFI_SUCCESS) {
+		pr_err("efitime: can't set timezone\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int efi_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+	long int gmtoff;
+	int err;
+
+	switch (cmd) {
+	case RTC_RD_GMTOFF:
+		err = efi_read_gmtoff(dev, &gmtoff);
+		if (err)
+			return err;
+		return put_user(gmtoff, (unsigned long __user *)arg);
+	case RTC_SET_GMTOFF:
+		return efi_set_gmtoff(dev, arg);
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return 0;
+}
+
 static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 {
 	efi_time_t eft;
@@ -172,6 +253,17 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm)
 {
 	efi_status_t status;
 	efi_time_t eft;
+#ifdef CONFIG_X86
+	efi_time_cap_t cap;
+
+	/* read time for grab timezone to avoid overwrite it */
+	status = efi.get_time(&eft, &cap);
+
+	if (status != EFI_SUCCESS) {
+		pr_err("efitime: can't read time\n");
+		return -EINVAL;
+	}
+#endif
 
 	convert_to_efi_time(tm, &eft);
 
@@ -181,13 +273,16 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm)
 }
 
 static const struct rtc_class_ops efi_rtc_ops = {
+#ifdef CONFIG_X86
+	.ioctl = efi_rtc_ioctl,
+#endif
 	.read_time = efi_read_time,
 	.set_time = efi_set_time,
 	.read_alarm = efi_read_alarm,
 	.set_alarm = efi_set_alarm,
 };
 
-static int __init efi_rtc_probe(struct platform_device *dev)
+static int efi_rtc_probe(struct platform_device *dev)
 {
 	struct rtc_device *rtc;
 
@@ -196,6 +291,8 @@ static int __init efi_rtc_probe(struct platform_device *dev)
 	if (IS_ERR(rtc))
 		return PTR_ERR(rtc);
 
+	rtc->caps = (RTC_TZ_CAP | RTC_DST_CAP);
+
 	platform_set_drvdata(dev, rtc);
 
 	return 0;
@@ -213,3 +310,4 @@ module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
 MODULE_AUTHOR("dann frazier <dannf@...com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("EFI RTC driver");
+MODULE_ALIAS("platform:rtc-efi");
-- 
1.6.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ