diff mbox

[v2] efi_runtime: add efi_runtime kernel driver module into fwts

Message ID 1348153386-16688-1-git-send-email-ivan.hu@canonical.com
State Rejected
Headers show

Commit Message

ivanhu Sept. 20, 2012, 3:03 p.m. UTC
efi_runtime kernel driver provides the runtime UEFI interfaces for fwts
to test the UEFI runtime service implementiation.
Current capabilities:
* provide the RT service interfaces:
   * GetVariable
   * SetVariable
   * GetTime
   * SetTime
   * GetWakeupTime
   * SetWakeupTime
   * GetNextVariableName

Signed-off-by: Ivan Hu <ivan.hu@canonical.com>
---
 efi_runtime/Makefile      |    6 +
 efi_runtime/efi_runtime.c |  310 +++++++++++++++++++++++++++++++++++++++++++++
 efi_runtime/efi_runtime.h |  112 ++++++++++++++++
 3 files changed, 428 insertions(+)
 create mode 100644 efi_runtime/Makefile
 create mode 100644 efi_runtime/efi_runtime.c
 create mode 100644 efi_runtime/efi_runtime.h

Comments

Colin Ian King Sept. 20, 2012, 5:47 p.m. UTC | #1
On 20/09/12 16:03, Ivan Hu wrote:
> efi_runtime kernel driver provides the runtime UEFI interfaces for fwts
> to test the UEFI runtime service implementiation.
> Current capabilities:
> * provide the RT service interfaces:
>     * GetVariable
>     * SetVariable
>     * GetTime
>     * SetTime
>     * GetWakeupTime
>     * SetWakeupTime
>     * GetNextVariableName
>
> Signed-off-by: Ivan Hu <ivan.hu@canonical.com>
> ---
>   efi_runtime/Makefile      |    6 +
>   efi_runtime/efi_runtime.c |  310 +++++++++++++++++++++++++++++++++++++++++++++
>   efi_runtime/efi_runtime.h |  112 ++++++++++++++++
>   3 files changed, 428 insertions(+)
>   create mode 100644 efi_runtime/Makefile
>   create mode 100644 efi_runtime/efi_runtime.c
>   create mode 100644 efi_runtime/efi_runtime.h
>
> diff --git a/efi_runtime/Makefile b/efi_runtime/Makefile
> new file mode 100644
> index 0000000..8ed7dea
> --- /dev/null
> +++ b/efi_runtime/Makefile
> @@ -0,0 +1,6 @@
> +obj-m += efi_runtime.o
> +all:
> +	make -C /lib/modules/`uname -r`/build M=`pwd` modules
> +
> +clean:
> +	make -C /lib/modules/`uname -r`/build M=`pwd` clean
> diff --git a/efi_runtime/efi_runtime.c b/efi_runtime/efi_runtime.c
> new file mode 100644
> index 0000000..901af42
> --- /dev/null
> +++ b/efi_runtime/efi_runtime.c
> @@ -0,0 +1,310 @@
> +/*
> + * EFI Runtime driver
> + *
> + * Copyright(C) 2012 Canonical Ltd.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/proc_fs.h>
> +#include <linux/efi.h>
> +
> +#include <linux/uaccess.h>
> +
> +#include "efi_runtime.h"
> +
> +#define EFI_FWTS_EFI_VERSION	"0.1"
> +
> +MODULE_AUTHOR("Ivan Hu");
> +MODULE_DESCRIPTION("EFI Runtime Driver");
> +MODULE_LICENSE("GPL");
> +
> +static void convert_from_efi_time(efi_time_t *eft, EFI_TIME *time)
> +{
> +	memset(time, 0, sizeof(EFI_TIME));
> +	time->Year = eft->year;
> +	time->Month = eft->month;
> +	time->Day  = eft->day;
> +	time->Hour = eft->hour;
> +	time->Minute = eft->minute;
> +	time->Second  = eft->second;
> +	time->Pad1 = eft->pad1;
> +	time->Nanosecond = eft->nanosecond;
> +	time->TimeZone = eft->timezone;
> +	time->Daylight = eft->daylight;
> +	time->Pad2 = eft->pad2;
> +}
> +
> +static void convert_to_efi_time(efi_time_t *eft, EFI_TIME *time)
> +{
> +	memset(eft, 0, sizeof(eft));
> +	eft->year = time->Year;
> +	eft->month = time->Month;
> +	eft->day = time->Day;
> +	eft->hour = time->Hour;
> +	eft->minute = time->Minute;
> +	eft->second = time->Second;
> +	eft->pad1 = time->Pad1;
> +	eft->nanosecond = time->Nanosecond;
> +	eft->timezone = time->TimeZone;
> +	eft->daylight = time->Daylight;
> +	eft->pad2 = time->Pad2;
> +}
> +
> +static void convert_from_guid(efi_guid_t *vendor, EFI_GUID *vendor_guid)
> +{
> +	int i;
> +	for (i = 0; i < 16; i++) {
> +		if (i < 4)
> +			vendor->b[i] = (vendor_guid->Data1 >> (8*i)) & 0xff;
> +		else if (i < 6)
> +			vendor->b[i] = (vendor_guid->Data2 >> (8*(i-4))) & 0xff;
> +		else if (i < 8)
> +			vendor->b[i] = (vendor_guid->Data3 >> (8*(i-6))) & 0xff;
> +		else
> +			vendor->b[i] = (vendor_guid->Data4[i-8]);
> +	}
> +}
> +
> +static void convert_to_guid(efi_guid_t *vendor, EFI_GUID *vendor_guid)
> +{
> +	int i;
> +	vendor_guid->Data1 = vendor->b[0] + (vendor->b[1] << 8) +
> +				(vendor->b[2] << 16) + (vendor->b[3] << 24);
> +	vendor_guid->Data2 = vendor->b[4] + (vendor->b[5] << 8);
> +	vendor_guid->Data3 = vendor->b[6] + (vendor->b[7] << 8);
> +	for (i = 0; i < 8; i++)
> +		vendor_guid->Data4[i] = vendor->b[i+8];
> +}
> +
> +static long efi_runtime_ioctl(struct file *file, unsigned int cmd,
> +							unsigned long arg)
> +{
> +	efi_status_t status;
> +	struct efi_getvariable __user *pgetvariable;
> +	struct efi_setvariable __user *psetvariable;
> +
> +	efi_guid_t vendor;
> +	EFI_GUID vendor_guid;
> +	unsigned long datasize;
> +	uint32_t attr;
> +
> +	efi_time_t eft;
> +	efi_time_cap_t cap;
> +	struct efi_gettime __user *pgettime;
> +	struct efi_settime __user *psettime;
> +
> +	unsigned char enabled, pending;
> +	EFI_TIME efi_time;
> +	struct efi_getwakeuptime __user *pgetwakeuptime;
> +	struct efi_setwakeuptime __user *psetwakeuptime;
> +
> +	struct efi_getnextvariablename __user *pgetnextvariablename;
> +	unsigned long name_size;
> +
> +	switch (cmd) {
> +	case EFI_RUNTIME_GET_VARIABLE:
> +		pgetvariable = (struct efi_getvariable __user *)arg;
> +
> +		if (get_user(datasize, pgetvariable->DataSize) ||
> +			copy_from_user(&vendor_guid, pgetvariable->VendorGuid,
> +							sizeof(EFI_GUID)))
> +			return -EFAULT;
> +
> +		convert_from_guid(&vendor, &vendor_guid);
> +		status = efi.get_variable(pgetvariable->VariableName, &vendor,
> +					&attr, &datasize, pgetvariable->Data);
> +
> +		if (status == EFI_SUCCESS) {
> +			if (put_user(attr, pgetvariable->Attributes) ||
> +				put_user(datasize, pgetvariable->DataSize))
> +				return -EFAULT;
> +			return status;
> +		} else {
> +			printk(KERN_ERR "efi_runtime: can't get variable\n");
> +			return status;
> +		}
> +
> +	case EFI_RUNTIME_SET_VARIABLE:
> +		psetvariable = (struct efi_setvariable __user *)arg;
> +		if (get_user(datasize, &psetvariable->DataSize) ||
> +			get_user(attr, &psetvariable->Attributes) ||
> +			copy_from_user(&vendor_guid, psetvariable->VendorGuid,
> +							sizeof(EFI_GUID)))
> +			return -EFAULT;
> +
> +		convert_from_guid(&vendor, &vendor_guid);
> +		status = efi.set_variable(psetvariable->VariableName, &vendor,
> +					attr, datasize, psetvariable->Data);
> +		return status;
> +
> +	case EFI_RUNTIME_GET_TIME:
> +		status = efi.get_time(&eft, &cap);
> +		if (status != EFI_SUCCESS) {
> +			printk(KERN_ERR "efitime: can't read time\n");
> +			return status;
> +		}
> +
> +		pgettime = (struct efi_gettime __user *)arg;
> +		if (put_user(cap.resolution,
> +					&pgettime->Capabilities->Resolution) ||
> +					put_user(cap.accuracy,
> +					&pgettime->Capabilities->Accuracy) ||
> +					put_user(cap.sets_to_zero,
> +					&pgettime->Capabilities->SetsToZero))
> +			return -EFAULT;
> +		return copy_to_user(pgettime->Time, &eft,
> +				sizeof(EFI_TIME)) ? -EFAULT : status;
> +
> +	case EFI_RUNTIME_SET_TIME:
> +
> +		psettime = (struct efi_settime __user *)arg;
> +		if (copy_from_user(&efi_time, psettime->Time,
> +						sizeof(EFI_TIME)))
> +			return -EFAULT;
> +		convert_to_efi_time(&eft, &efi_time);
> +		status = efi.set_time(&eft);
> +		return status == EFI_SUCCESS ? status : -EINVAL;
> +
> +	case EFI_RUNTIME_GET_WAKETIME:
> +
> +		status = efi.get_wakeup_time((efi_bool_t *)&enabled,
> +						(efi_bool_t *)&pending, &eft);
> +
> +		if (status != EFI_SUCCESS)
> +			return status;
> +
> +		pgetwakeuptime = (struct efi_getwakeuptime __user *)arg;
> +
> +		if (put_user(enabled, pgetwakeuptime->Enabled) ||
> +				put_user(pending, pgetwakeuptime->Pending))
> +			return -EFAULT;
> +
> +		convert_from_efi_time(&eft, &efi_time);
> +
> +		return copy_to_user(pgetwakeuptime->Time, &efi_time,
> +				sizeof(EFI_TIME)) ? -EFAULT : status;
> +
> +	case EFI_RUNTIME_SET_WAKETIME:
> +
> +		psetwakeuptime = (struct efi_setwakeuptime __user *)arg;
> +
> +		if (get_user(enabled, &psetwakeuptime->Enabled) ||
> +					copy_from_user(&efi_time,
> +					psetwakeuptime->Time,
> +					sizeof(EFI_TIME)))
> +			return -EFAULT;
> +
> +		convert_to_efi_time(&eft, &efi_time);
> +
> +		status = efi.set_wakeup_time(enabled, &eft);
> +
> +		return status == EFI_SUCCESS ? status : -EINVAL;
> +
> +	case EFI_RUNTIME_GET_NEXTVARIABLENAME:
> +
> +		pgetnextvariablename = (struct efi_getnextvariablename
> +								__user *)arg;
> +
> +		if (get_user(name_size, pgetnextvariablename->VariableNameSize)
> +				|| copy_from_user(&vendor_guid,
> +					pgetnextvariablename->VendorGuid,
> +					sizeof(EFI_GUID)))
> +			return -EFAULT;
> +		if (name_size > 1024)
> +			return -EFAULT;
> +
> +		convert_from_guid(&vendor, &vendor_guid);
> +
> +		status = efi.get_next_variable(&name_size,
> +					pgetnextvariablename->VariableName,
> +								&vendor);
> +
> +		if (status != EFI_SUCCESS)
> +			return status;
> +		convert_to_guid(&vendor, &vendor_guid);
> +
> +		if (put_user(name_size, pgetnextvariablename->VariableNameSize))
> +			return -EFAULT;
> +
> +		if (copy_to_user(pgetnextvariablename->VendorGuid,
> +						&vendor_guid, sizeof(EFI_GUID)))
> +			return -EFAULT;
> +		return status;
> +	}
> +
> +	return -ENOTTY;
> +}


OK, so efi_runtime_ioctl() returns a signed long, but the code is 
actually returning status which is an efi_status which is an unsigned 
long.  What happens if the efi status has the top bit set? .. this would 
return a -ve value which looks like an error.  I think we need to see if 
this makes sense or not - what is the range of return values from 
underling EFI calls?


> +
> +static int efi_runtime_open(struct inode *inode, struct file *file)
> +{
> +	/*
> +	 * nothing special to do here
> +	 * We do accept multiple open files at the same time as we
> +	 * synchronize on the per call operation.
> +	 */
> +	return 0;
> +}
> +
> +static int efi_runtime_close(struct inode *inode, struct file *file)
> +{
> +	return 0;
> +}
> +
> +/*
> + *	The various file operations we support.
> + */
> +static const struct file_operations efi_runtime_fops = {
> +	.owner		= THIS_MODULE,
> +	.unlocked_ioctl	= efi_runtime_ioctl,
> +	.open		= efi_runtime_open,
> +	.release	= efi_runtime_close,
> +	.llseek		= no_llseek,
> +};
> +
> +static struct miscdevice efi_runtime_dev = {
> +	MISC_DYNAMIC_MINOR,
> +	"efi_runtime",
> +	&efi_runtime_fops
> +};
> +
> +static int __init efi_runtime_init(void)
> +{
> +	int ret;
> +
> +	printk(KERN_INFO "EFI_RUNTIME Driver v%s\n", EFI_FWTS_EFI_VERSION);
> +
> +	ret = misc_register(&efi_runtime_dev);
> +	if (ret) {
> +		printk(KERN_ERR "efi_runtime: can't misc_register on minor=%d\n",
> +				MISC_DYNAMIC_MINOR);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void __exit efi_runtime_exit(void)
> +{
> +	printk(KERN_INFO "EFI_RUNTIME Driver Exit.\n");
> +	misc_deregister(&efi_runtime_dev);
> +}
> +
> +module_init(efi_runtime_init);
> +module_exit(efi_runtime_exit);
> +
> diff --git a/efi_runtime/efi_runtime.h b/efi_runtime/efi_runtime.h
> new file mode 100644
> index 0000000..0766916
> --- /dev/null
> +++ b/efi_runtime/efi_runtime.h
> @@ -0,0 +1,112 @@
> +/*
> + * EFI Runtime driver
> + *
> + * Copyright(C) 2012 Canonical Ltd.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef _EFI_RUNTIME_H_
> +#define _EFI_RUNTIME_H_
> +
> +typedef struct {
> +	uint32_t	Data1;
> +	uint16_t	Data2;
> +	uint16_t	Data3;
> +	uint8_t		Data4[8];
> +} __attribute__ ((packed)) EFI_GUID;
> +
> +typedef struct {
> +	uint16_t	Year;		/* 1900 – 9999 */
> +	uint8_t		Month;		/* 1 – 12 */
> +	uint8_t		Day;		/* 1 – 31 */
> +	uint8_t		Hour;		/* 0 – 23 */
> +	uint8_t		Minute;		/* 0 – 59 */
> +	uint8_t		Second;		/* 0 – 59 */
> +	uint8_t		Pad1;
> +	uint32_t	Nanosecond;	/* 0 – 999,999,999 */
> +	int16_t		TimeZone;	/* -1440 to 1440 or 2047 */
> +	uint8_t		Daylight;
> +	uint8_t		Pad2;
> +} __attribute__ ((packed)) EFI_TIME;
> +
> +typedef struct {
> +	uint32_t	Resolution;
> +	uint32_t	Accuracy;
> +	uint8_t		SetsToZero;
> +} __attribute__ ((packed)) EFI_TIME_CAPABILITIES;
> +
> +struct efi_getvariable {
> +	uint16_t	*VariableName;
> +	EFI_GUID	*VendorGuid;
> +	uint32_t	*Attributes;
> +	uint64_t	*DataSize;
> +	void		*Data;
> +} __attribute__ ((packed));
> +
> +struct efi_setvariable {
> +	uint16_t	*VariableName;
> +	EFI_GUID	*VendorGuid;
> +	uint32_t	Attributes;
> +	uint64_t	DataSize;
> +	void		*Data;
> +} __attribute__ ((packed));
> +
> +struct efi_getnextvariablename {
> +	uint64_t	*VariableNameSize;
> +	uint16_t	*VariableName;
> +	EFI_GUID	*VendorGuid;
> +} __attribute__ ((packed));
> +
> +struct efi_gettime {
> +	EFI_TIME		*Time;
> +	EFI_TIME_CAPABILITIES	*Capabilities;
> +} __attribute__ ((packed));
> +
> +struct efi_settime {
> +	EFI_TIME		*Time;
> +} __attribute__ ((packed));
> +
> +struct efi_getwakeuptime {
> +	uint8_t		*Enabled;
> +	uint8_t		*Pending;
> +	EFI_TIME	*Time;
> +} __attribute__ ((packed));
> +
> +struct efi_setwakeuptime {
> +	uint8_t		Enabled;
> +	EFI_TIME	*Time;
> +} __attribute__ ((packed));
> +
> +/* ioctl calls that are permitted to the /dev/efi_runtime interface. */
> +#define EFI_RUNTIME_GET_VARIABLE \
> +	_IOWR('p', 0x01, struct efi_getvariable)
> +#define EFI_RUNTIME_SET_VARIABLE \
> +	_IOW('p', 0x02, struct efi_setvariable)
> +
> +#define EFI_RUNTIME_GET_TIME \
> +	_IOR('p', 0x03, struct efi_gettime)
> +#define EFI_RUNTIME_SET_TIME \
> +	_IOW('p', 0x04, struct efi_settime)
> +
> +#define EFI_RUNTIME_GET_WAKETIME \
> +	_IOR('p', 0x05, struct efi_getwakeuptime)
> +#define EFI_RUNTIME_SET_WAKETIME \
> +	_IOW('p', 0x06, struct efi_setwakeuptime)
> +
> +#define EFI_RUNTIME_GET_NEXTVARIABLENAME \
> +	_IOWR('p', 0x07, struct efi_getnextvariablename)
> +
> +#endif /* _EFI_RUNTIME_H_ */
>
ivanhu Sept. 21, 2012, 1:53 a.m. UTC | #2
On 09/21/2012 01:47 AM, Colin Ian King wrote:
> On 20/09/12 16:03, Ivan Hu wrote:
>> efi_runtime kernel driver provides the runtime UEFI interfaces for fwts
>> to test the UEFI runtime service implementiation.
>> Current capabilities:
>> * provide the RT service interfaces:
>>     * GetVariable
>>     * SetVariable
>>     * GetTime
>>     * SetTime
>>     * GetWakeupTime
>>     * SetWakeupTime
>>     * GetNextVariableName
>>
>> Signed-off-by: Ivan Hu <ivan.hu@canonical.com>
>> ---
>>   efi_runtime/Makefile      |    6 +
>>   efi_runtime/efi_runtime.c |  310
>> +++++++++++++++++++++++++++++++++++++++++++++
>>   efi_runtime/efi_runtime.h |  112 ++++++++++++++++
>>   3 files changed, 428 insertions(+)
>>   create mode 100644 efi_runtime/Makefile
>>   create mode 100644 efi_runtime/efi_runtime.c
>>   create mode 100644 efi_runtime/efi_runtime.h
>>
>> diff --git a/efi_runtime/Makefile b/efi_runtime/Makefile
>> new file mode 100644
>> index 0000000..8ed7dea
>> --- /dev/null
>> +++ b/efi_runtime/Makefile
>> @@ -0,0 +1,6 @@
>> +obj-m += efi_runtime.o
>> +all:
>> +    make -C /lib/modules/`uname -r`/build M=`pwd` modules
>> +
>> +clean:
>> +    make -C /lib/modules/`uname -r`/build M=`pwd` clean
>> diff --git a/efi_runtime/efi_runtime.c b/efi_runtime/efi_runtime.c
>> new file mode 100644
>> index 0000000..901af42
>> --- /dev/null
>> +++ b/efi_runtime/efi_runtime.c
>> @@ -0,0 +1,310 @@
>> +/*
>> + * EFI Runtime driver
>> + *
>> + * Copyright(C) 2012 Canonical Ltd.
>> + *
>> + *  This program is free software; you can redistribute it and/or modify
>> + *  it under the terms of the GNU General Public License as published by
>> + *  the Free Software Foundation; either version 2 of the License, or
>> + *  (at your option) any later version.
>> + *
>> + *  This program is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + *  GNU General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU General Public License
>> + *  along with this program; if not, write to the Free Software
>> + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
>> 02111-1307  USA
>> + */
>> +
>> +#include <linux/miscdevice.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/proc_fs.h>
>> +#include <linux/efi.h>
>> +
>> +#include <linux/uaccess.h>
>> +
>> +#include "efi_runtime.h"
>> +
>> +#define EFI_FWTS_EFI_VERSION    "0.1"
>> +
>> +MODULE_AUTHOR("Ivan Hu");
>> +MODULE_DESCRIPTION("EFI Runtime Driver");
>> +MODULE_LICENSE("GPL");
>> +
>> +static void convert_from_efi_time(efi_time_t *eft, EFI_TIME *time)
>> +{
>> +    memset(time, 0, sizeof(EFI_TIME));
>> +    time->Year = eft->year;
>> +    time->Month = eft->month;
>> +    time->Day  = eft->day;
>> +    time->Hour = eft->hour;
>> +    time->Minute = eft->minute;
>> +    time->Second  = eft->second;
>> +    time->Pad1 = eft->pad1;
>> +    time->Nanosecond = eft->nanosecond;
>> +    time->TimeZone = eft->timezone;
>> +    time->Daylight = eft->daylight;
>> +    time->Pad2 = eft->pad2;
>> +}
>> +
>> +static void convert_to_efi_time(efi_time_t *eft, EFI_TIME *time)
>> +{
>> +    memset(eft, 0, sizeof(eft));
>> +    eft->year = time->Year;
>> +    eft->month = time->Month;
>> +    eft->day = time->Day;
>> +    eft->hour = time->Hour;
>> +    eft->minute = time->Minute;
>> +    eft->second = time->Second;
>> +    eft->pad1 = time->Pad1;
>> +    eft->nanosecond = time->Nanosecond;
>> +    eft->timezone = time->TimeZone;
>> +    eft->daylight = time->Daylight;
>> +    eft->pad2 = time->Pad2;
>> +}
>> +
>> +static void convert_from_guid(efi_guid_t *vendor, EFI_GUID *vendor_guid)
>> +{
>> +    int i;
>> +    for (i = 0; i < 16; i++) {
>> +        if (i < 4)
>> +            vendor->b[i] = (vendor_guid->Data1 >> (8*i)) & 0xff;
>> +        else if (i < 6)
>> +            vendor->b[i] = (vendor_guid->Data2 >> (8*(i-4))) & 0xff;
>> +        else if (i < 8)
>> +            vendor->b[i] = (vendor_guid->Data3 >> (8*(i-6))) & 0xff;
>> +        else
>> +            vendor->b[i] = (vendor_guid->Data4[i-8]);
>> +    }
>> +}
>> +
>> +static void convert_to_guid(efi_guid_t *vendor, EFI_GUID *vendor_guid)
>> +{
>> +    int i;
>> +    vendor_guid->Data1 = vendor->b[0] + (vendor->b[1] << 8) +
>> +                (vendor->b[2] << 16) + (vendor->b[3] << 24);
>> +    vendor_guid->Data2 = vendor->b[4] + (vendor->b[5] << 8);
>> +    vendor_guid->Data3 = vendor->b[6] + (vendor->b[7] << 8);
>> +    for (i = 0; i < 8; i++)
>> +        vendor_guid->Data4[i] = vendor->b[i+8];
>> +}
>> +
>> +static long efi_runtime_ioctl(struct file *file, unsigned int cmd,
>> +                            unsigned long arg)
>> +{
>> +    efi_status_t status;
>> +    struct efi_getvariable __user *pgetvariable;
>> +    struct efi_setvariable __user *psetvariable;
>> +
>> +    efi_guid_t vendor;
>> +    EFI_GUID vendor_guid;
>> +    unsigned long datasize;
>> +    uint32_t attr;
>> +
>> +    efi_time_t eft;
>> +    efi_time_cap_t cap;
>> +    struct efi_gettime __user *pgettime;
>> +    struct efi_settime __user *psettime;
>> +
>> +    unsigned char enabled, pending;
>> +    EFI_TIME efi_time;
>> +    struct efi_getwakeuptime __user *pgetwakeuptime;
>> +    struct efi_setwakeuptime __user *psetwakeuptime;
>> +
>> +    struct efi_getnextvariablename __user *pgetnextvariablename;
>> +    unsigned long name_size;
>> +
>> +    switch (cmd) {
>> +    case EFI_RUNTIME_GET_VARIABLE:
>> +        pgetvariable = (struct efi_getvariable __user *)arg;
>> +
>> +        if (get_user(datasize, pgetvariable->DataSize) ||
>> +            copy_from_user(&vendor_guid, pgetvariable->VendorGuid,
>> +                            sizeof(EFI_GUID)))
>> +            return -EFAULT;
>> +
>> +        convert_from_guid(&vendor, &vendor_guid);
>> +        status = efi.get_variable(pgetvariable->VariableName, &vendor,
>> +                    &attr, &datasize, pgetvariable->Data);
>> +
>> +        if (status == EFI_SUCCESS) {
>> +            if (put_user(attr, pgetvariable->Attributes) ||
>> +                put_user(datasize, pgetvariable->DataSize))
>> +                return -EFAULT;
>> +            return status;
>> +        } else {
>> +            printk(KERN_ERR "efi_runtime: can't get variable\n");
>> +            return status;
>> +        }
>> +
>> +    case EFI_RUNTIME_SET_VARIABLE:
>> +        psetvariable = (struct efi_setvariable __user *)arg;
>> +        if (get_user(datasize, &psetvariable->DataSize) ||
>> +            get_user(attr, &psetvariable->Attributes) ||
>> +            copy_from_user(&vendor_guid, psetvariable->VendorGuid,
>> +                            sizeof(EFI_GUID)))
>> +            return -EFAULT;
>> +
>> +        convert_from_guid(&vendor, &vendor_guid);
>> +        status = efi.set_variable(psetvariable->VariableName, &vendor,
>> +                    attr, datasize, psetvariable->Data);
>> +        return status;
>> +
>> +    case EFI_RUNTIME_GET_TIME:
>> +        status = efi.get_time(&eft, &cap);
>> +        if (status != EFI_SUCCESS) {
>> +            printk(KERN_ERR "efitime: can't read time\n");
>> +            return status;
>> +        }
>> +
>> +        pgettime = (struct efi_gettime __user *)arg;
>> +        if (put_user(cap.resolution,
>> +                    &pgettime->Capabilities->Resolution) ||
>> +                    put_user(cap.accuracy,
>> +                    &pgettime->Capabilities->Accuracy) ||
>> +                    put_user(cap.sets_to_zero,
>> +                    &pgettime->Capabilities->SetsToZero))
>> +            return -EFAULT;
>> +        return copy_to_user(pgettime->Time, &eft,
>> +                sizeof(EFI_TIME)) ? -EFAULT : status;
>> +
>> +    case EFI_RUNTIME_SET_TIME:
>> +
>> +        psettime = (struct efi_settime __user *)arg;
>> +        if (copy_from_user(&efi_time, psettime->Time,
>> +                        sizeof(EFI_TIME)))
>> +            return -EFAULT;
>> +        convert_to_efi_time(&eft, &efi_time);
>> +        status = efi.set_time(&eft);
>> +        return status == EFI_SUCCESS ? status : -EINVAL;
>> +
>> +    case EFI_RUNTIME_GET_WAKETIME:
>> +
>> +        status = efi.get_wakeup_time((efi_bool_t *)&enabled,
>> +                        (efi_bool_t *)&pending, &eft);
>> +
>> +        if (status != EFI_SUCCESS)
>> +            return status;
>> +
>> +        pgetwakeuptime = (struct efi_getwakeuptime __user *)arg;
>> +
>> +        if (put_user(enabled, pgetwakeuptime->Enabled) ||
>> +                put_user(pending, pgetwakeuptime->Pending))
>> +            return -EFAULT;
>> +
>> +        convert_from_efi_time(&eft, &efi_time);
>> +
>> +        return copy_to_user(pgetwakeuptime->Time, &efi_time,
>> +                sizeof(EFI_TIME)) ? -EFAULT : status;
>> +
>> +    case EFI_RUNTIME_SET_WAKETIME:
>> +
>> +        psetwakeuptime = (struct efi_setwakeuptime __user *)arg;
>> +
>> +        if (get_user(enabled, &psetwakeuptime->Enabled) ||
>> +                    copy_from_user(&efi_time,
>> +                    psetwakeuptime->Time,
>> +                    sizeof(EFI_TIME)))
>> +            return -EFAULT;
>> +
>> +        convert_to_efi_time(&eft, &efi_time);
>> +
>> +        status = efi.set_wakeup_time(enabled, &eft);
>> +
>> +        return status == EFI_SUCCESS ? status : -EINVAL;
>> +
>> +    case EFI_RUNTIME_GET_NEXTVARIABLENAME:
>> +
>> +        pgetnextvariablename = (struct efi_getnextvariablename
>> +                                __user *)arg;
>> +
>> +        if (get_user(name_size, pgetnextvariablename->VariableNameSize)
>> +                || copy_from_user(&vendor_guid,
>> +                    pgetnextvariablename->VendorGuid,
>> +                    sizeof(EFI_GUID)))
>> +            return -EFAULT;
>> +        if (name_size > 1024)
>> +            return -EFAULT;
>> +
>> +        convert_from_guid(&vendor, &vendor_guid);
>> +
>> +        status = efi.get_next_variable(&name_size,
>> +                    pgetnextvariablename->VariableName,
>> +                                &vendor);
>> +
>> +        if (status != EFI_SUCCESS)
>> +            return status;
>> +        convert_to_guid(&vendor, &vendor_guid);
>> +
>> +        if (put_user(name_size, pgetnextvariablename->VariableNameSize))
>> +            return -EFAULT;
>> +
>> +        if (copy_to_user(pgetnextvariablename->VendorGuid,
>> +                        &vendor_guid, sizeof(EFI_GUID)))
>> +            return -EFAULT;
>> +        return status;
>> +    }
>> +
>> +    return -ENOTTY;
>> +}
>
>
> OK, so efi_runtime_ioctl() returns a signed long, but the code is
> actually returning status which is an efi_status which is an unsigned
> long.  What happens if the efi status has the top bit set? .. this would
> return a -ve value which looks like an error.  I think we need to see if
> this makes sense or not - what is the range of return values from
> underling EFI calls?
>
>

yup, I noticed this as well, actually, this is a temporary solution. The 
high bit of return value means EFI_STATUS Success Codes (High Bit Clear) 
or EFI_STATUS Warning Codes (High Bit Clear), I ignore the high bit 
here. So if we get the status in user space, we get two possibilities 
(error or warning).
I am planing to put the efi_status into each structures and return to 
user space. Is that make sense to you? or any suggestion? :)

>> +
>> +static int efi_runtime_open(struct inode *inode, struct file *file)
>> +{
>> +    /*
>> +     * nothing special to do here
>> +     * We do accept multiple open files at the same time as we
>> +     * synchronize on the per call operation.
>> +     */
>> +    return 0;
>> +}
>> +
>> +static int efi_runtime_close(struct inode *inode, struct file *file)
>> +{
>> +    return 0;
>> +}
>> +
>> +/*
>> + *    The various file operations we support.
>> + */
>> +static const struct file_operations efi_runtime_fops = {
>> +    .owner        = THIS_MODULE,
>> +    .unlocked_ioctl    = efi_runtime_ioctl,
>> +    .open        = efi_runtime_open,
>> +    .release    = efi_runtime_close,
>> +    .llseek        = no_llseek,
>> +};
>> +
>> +static struct miscdevice efi_runtime_dev = {
>> +    MISC_DYNAMIC_MINOR,
>> +    "efi_runtime",
>> +    &efi_runtime_fops
>> +};
>> +
>> +static int __init efi_runtime_init(void)
>> +{
>> +    int ret;
>> +
>> +    printk(KERN_INFO "EFI_RUNTIME Driver v%s\n", EFI_FWTS_EFI_VERSION);
>> +
>> +    ret = misc_register(&efi_runtime_dev);
>> +    if (ret) {
>> +        printk(KERN_ERR "efi_runtime: can't misc_register on
>> minor=%d\n",
>> +                MISC_DYNAMIC_MINOR);
>> +        return ret;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void __exit efi_runtime_exit(void)
>> +{
>> +    printk(KERN_INFO "EFI_RUNTIME Driver Exit.\n");
>> +    misc_deregister(&efi_runtime_dev);
>> +}
>> +
>> +module_init(efi_runtime_init);
>> +module_exit(efi_runtime_exit);
>> +
>> diff --git a/efi_runtime/efi_runtime.h b/efi_runtime/efi_runtime.h
>> new file mode 100644
>> index 0000000..0766916
>> --- /dev/null
>> +++ b/efi_runtime/efi_runtime.h
>> @@ -0,0 +1,112 @@
>> +/*
>> + * EFI Runtime driver
>> + *
>> + * Copyright(C) 2012 Canonical Ltd.
>> + *
>> + *  This program is free software; you can redistribute it and/or modify
>> + *  it under the terms of the GNU General Public License as published by
>> + *  the Free Software Foundation; either version 2 of the License, or
>> + *  (at your option) any later version.
>> + *
>> + *  This program is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + *  GNU General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU General Public License
>> + *  along with this program; if not, write to the Free Software
>> + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
>> 02111-1307  USA
>> + */
>> +
>> +#ifndef _EFI_RUNTIME_H_
>> +#define _EFI_RUNTIME_H_
>> +
>> +typedef struct {
>> +    uint32_t    Data1;
>> +    uint16_t    Data2;
>> +    uint16_t    Data3;
>> +    uint8_t        Data4[8];
>> +} __attribute__ ((packed)) EFI_GUID;
>> +
>> +typedef struct {
>> +    uint16_t    Year;        /* 1900 – 9999 */
>> +    uint8_t        Month;        /* 1 – 12 */
>> +    uint8_t        Day;        /* 1 – 31 */
>> +    uint8_t        Hour;        /* 0 – 23 */
>> +    uint8_t        Minute;        /* 0 – 59 */
>> +    uint8_t        Second;        /* 0 – 59 */
>> +    uint8_t        Pad1;
>> +    uint32_t    Nanosecond;    /* 0 – 999,999,999 */
>> +    int16_t        TimeZone;    /* -1440 to 1440 or 2047 */
>> +    uint8_t        Daylight;
>> +    uint8_t        Pad2;
>> +} __attribute__ ((packed)) EFI_TIME;
>> +
>> +typedef struct {
>> +    uint32_t    Resolution;
>> +    uint32_t    Accuracy;
>> +    uint8_t        SetsToZero;
>> +} __attribute__ ((packed)) EFI_TIME_CAPABILITIES;
>> +
>> +struct efi_getvariable {
>> +    uint16_t    *VariableName;
>> +    EFI_GUID    *VendorGuid;
>> +    uint32_t    *Attributes;
>> +    uint64_t    *DataSize;
>> +    void        *Data;
>> +} __attribute__ ((packed));
>> +
>> +struct efi_setvariable {
>> +    uint16_t    *VariableName;
>> +    EFI_GUID    *VendorGuid;
>> +    uint32_t    Attributes;
>> +    uint64_t    DataSize;
>> +    void        *Data;
>> +} __attribute__ ((packed));
>> +
>> +struct efi_getnextvariablename {
>> +    uint64_t    *VariableNameSize;
>> +    uint16_t    *VariableName;
>> +    EFI_GUID    *VendorGuid;
>> +} __attribute__ ((packed));
>> +
>> +struct efi_gettime {
>> +    EFI_TIME        *Time;
>> +    EFI_TIME_CAPABILITIES    *Capabilities;
>> +} __attribute__ ((packed));
>> +
>> +struct efi_settime {
>> +    EFI_TIME        *Time;
>> +} __attribute__ ((packed));
>> +
>> +struct efi_getwakeuptime {
>> +    uint8_t        *Enabled;
>> +    uint8_t        *Pending;
>> +    EFI_TIME    *Time;
>> +} __attribute__ ((packed));
>> +
>> +struct efi_setwakeuptime {
>> +    uint8_t        Enabled;
>> +    EFI_TIME    *Time;
>> +} __attribute__ ((packed));
>> +
>> +/* ioctl calls that are permitted to the /dev/efi_runtime interface. */
>> +#define EFI_RUNTIME_GET_VARIABLE \
>> +    _IOWR('p', 0x01, struct efi_getvariable)
>> +#define EFI_RUNTIME_SET_VARIABLE \
>> +    _IOW('p', 0x02, struct efi_setvariable)
>> +
>> +#define EFI_RUNTIME_GET_TIME \
>> +    _IOR('p', 0x03, struct efi_gettime)
>> +#define EFI_RUNTIME_SET_TIME \
>> +    _IOW('p', 0x04, struct efi_settime)
>> +
>> +#define EFI_RUNTIME_GET_WAKETIME \
>> +    _IOR('p', 0x05, struct efi_getwakeuptime)
>> +#define EFI_RUNTIME_SET_WAKETIME \
>> +    _IOW('p', 0x06, struct efi_setwakeuptime)
>> +
>> +#define EFI_RUNTIME_GET_NEXTVARIABLENAME \
>> +    _IOWR('p', 0x07, struct efi_getnextvariablename)
>> +
>> +#endif /* _EFI_RUNTIME_H_ */
>>
>
>
Colin Ian King Sept. 21, 2012, 8:53 a.m. UTC | #3
On 21/09/12 02:53, IvanHu wrote:
> On 09/21/2012 01:47 AM, Colin Ian King wrote:
>> On 20/09/12 16:03, Ivan Hu wrote:
>>> efi_runtime kernel driver provides the runtime UEFI interfaces for fwts
>>> to test the UEFI runtime service implementiation.
>>> Current capabilities:
>>> * provide the RT service interfaces:
>>>     * GetVariable
>>>     * SetVariable
>>>     * GetTime
>>>     * SetTime
>>>     * GetWakeupTime
>>>     * SetWakeupTime
>>>     * GetNextVariableName
>>>
>>> Signed-off-by: Ivan Hu <ivan.hu@canonical.com>
>>> ---
>>>   efi_runtime/Makefile      |    6 +
>>>   efi_runtime/efi_runtime.c |  310
>>> +++++++++++++++++++++++++++++++++++++++++++++
>>>   efi_runtime/efi_runtime.h |  112 ++++++++++++++++
>>>   3 files changed, 428 insertions(+)
>>>   create mode 100644 efi_runtime/Makefile
>>>   create mode 100644 efi_runtime/efi_runtime.c
>>>   create mode 100644 efi_runtime/efi_runtime.h
>>>
>>> diff --git a/efi_runtime/Makefile b/efi_runtime/Makefile
>>> new file mode 100644
>>> index 0000000..8ed7dea
>>> --- /dev/null
>>> +++ b/efi_runtime/Makefile
>>> @@ -0,0 +1,6 @@
>>> +obj-m += efi_runtime.o
>>> +all:
>>> +    make -C /lib/modules/`uname -r`/build M=`pwd` modules
>>> +
>>> +clean:
>>> +    make -C /lib/modules/`uname -r`/build M=`pwd` clean
>>> diff --git a/efi_runtime/efi_runtime.c b/efi_runtime/efi_runtime.c
>>> new file mode 100644
>>> index 0000000..901af42
>>> --- /dev/null
>>> +++ b/efi_runtime/efi_runtime.c
>>> @@ -0,0 +1,310 @@
>>> +/*
>>> + * EFI Runtime driver
>>> + *
>>> + * Copyright(C) 2012 Canonical Ltd.
>>> + *
>>> + *  This program is free software; you can redistribute it and/or
>>> modify
>>> + *  it under the terms of the GNU General Public License as
>>> published by
>>> + *  the Free Software Foundation; either version 2 of the License, or
>>> + *  (at your option) any later version.
>>> + *
>>> + *  This program is distributed in the hope that it will be useful,
>>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + *  GNU General Public License for more details.
>>> + *
>>> + *  You should have received a copy of the GNU General Public License
>>> + *  along with this program; if not, write to the Free Software
>>> + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
>>> 02111-1307  USA
>>> + */
>>> +
>>> +#include <linux/miscdevice.h>
>>> +#include <linux/module.h>
>>> +#include <linux/init.h>
>>> +#include <linux/proc_fs.h>
>>> +#include <linux/efi.h>
>>> +
>>> +#include <linux/uaccess.h>
>>> +
>>> +#include "efi_runtime.h"
>>> +
>>> +#define EFI_FWTS_EFI_VERSION    "0.1"
>>> +
>>> +MODULE_AUTHOR("Ivan Hu");
>>> +MODULE_DESCRIPTION("EFI Runtime Driver");
>>> +MODULE_LICENSE("GPL");
>>> +
>>> +static void convert_from_efi_time(efi_time_t *eft, EFI_TIME *time)
>>> +{
>>> +    memset(time, 0, sizeof(EFI_TIME));
>>> +    time->Year = eft->year;
>>> +    time->Month = eft->month;
>>> +    time->Day  = eft->day;
>>> +    time->Hour = eft->hour;
>>> +    time->Minute = eft->minute;
>>> +    time->Second  = eft->second;
>>> +    time->Pad1 = eft->pad1;
>>> +    time->Nanosecond = eft->nanosecond;
>>> +    time->TimeZone = eft->timezone;
>>> +    time->Daylight = eft->daylight;
>>> +    time->Pad2 = eft->pad2;
>>> +}
>>> +
>>> +static void convert_to_efi_time(efi_time_t *eft, EFI_TIME *time)
>>> +{
>>> +    memset(eft, 0, sizeof(eft));
>>> +    eft->year = time->Year;
>>> +    eft->month = time->Month;
>>> +    eft->day = time->Day;
>>> +    eft->hour = time->Hour;
>>> +    eft->minute = time->Minute;
>>> +    eft->second = time->Second;
>>> +    eft->pad1 = time->Pad1;
>>> +    eft->nanosecond = time->Nanosecond;
>>> +    eft->timezone = time->TimeZone;
>>> +    eft->daylight = time->Daylight;
>>> +    eft->pad2 = time->Pad2;
>>> +}
>>> +
>>> +static void convert_from_guid(efi_guid_t *vendor, EFI_GUID
>>> *vendor_guid)
>>> +{
>>> +    int i;
>>> +    for (i = 0; i < 16; i++) {
>>> +        if (i < 4)
>>> +            vendor->b[i] = (vendor_guid->Data1 >> (8*i)) & 0xff;
>>> +        else if (i < 6)
>>> +            vendor->b[i] = (vendor_guid->Data2 >> (8*(i-4))) & 0xff;
>>> +        else if (i < 8)
>>> +            vendor->b[i] = (vendor_guid->Data3 >> (8*(i-6))) & 0xff;
>>> +        else
>>> +            vendor->b[i] = (vendor_guid->Data4[i-8]);
>>> +    }
>>> +}
>>> +
>>> +static void convert_to_guid(efi_guid_t *vendor, EFI_GUID *vendor_guid)
>>> +{
>>> +    int i;
>>> +    vendor_guid->Data1 = vendor->b[0] + (vendor->b[1] << 8) +
>>> +                (vendor->b[2] << 16) + (vendor->b[3] << 24);
>>> +    vendor_guid->Data2 = vendor->b[4] + (vendor->b[5] << 8);
>>> +    vendor_guid->Data3 = vendor->b[6] + (vendor->b[7] << 8);
>>> +    for (i = 0; i < 8; i++)
>>> +        vendor_guid->Data4[i] = vendor->b[i+8];
>>> +}
>>> +
>>> +static long efi_runtime_ioctl(struct file *file, unsigned int cmd,
>>> +                            unsigned long arg)
>>> +{
>>> +    efi_status_t status;
>>> +    struct efi_getvariable __user *pgetvariable;
>>> +    struct efi_setvariable __user *psetvariable;
>>> +
>>> +    efi_guid_t vendor;
>>> +    EFI_GUID vendor_guid;
>>> +    unsigned long datasize;
>>> +    uint32_t attr;
>>> +
>>> +    efi_time_t eft;
>>> +    efi_time_cap_t cap;
>>> +    struct efi_gettime __user *pgettime;
>>> +    struct efi_settime __user *psettime;
>>> +
>>> +    unsigned char enabled, pending;
>>> +    EFI_TIME efi_time;
>>> +    struct efi_getwakeuptime __user *pgetwakeuptime;
>>> +    struct efi_setwakeuptime __user *psetwakeuptime;
>>> +
>>> +    struct efi_getnextvariablename __user *pgetnextvariablename;
>>> +    unsigned long name_size;
>>> +
>>> +    switch (cmd) {
>>> +    case EFI_RUNTIME_GET_VARIABLE:
>>> +        pgetvariable = (struct efi_getvariable __user *)arg;
>>> +
>>> +        if (get_user(datasize, pgetvariable->DataSize) ||
>>> +            copy_from_user(&vendor_guid, pgetvariable->VendorGuid,
>>> +                            sizeof(EFI_GUID)))
>>> +            return -EFAULT;
>>> +
>>> +        convert_from_guid(&vendor, &vendor_guid);
>>> +        status = efi.get_variable(pgetvariable->VariableName, &vendor,
>>> +                    &attr, &datasize, pgetvariable->Data);
>>> +
>>> +        if (status == EFI_SUCCESS) {
>>> +            if (put_user(attr, pgetvariable->Attributes) ||
>>> +                put_user(datasize, pgetvariable->DataSize))
>>> +                return -EFAULT;
>>> +            return status;
>>> +        } else {
>>> +            printk(KERN_ERR "efi_runtime: can't get variable\n");
>>> +            return status;
>>> +        }
>>> +
>>> +    case EFI_RUNTIME_SET_VARIABLE:
>>> +        psetvariable = (struct efi_setvariable __user *)arg;
>>> +        if (get_user(datasize, &psetvariable->DataSize) ||
>>> +            get_user(attr, &psetvariable->Attributes) ||
>>> +            copy_from_user(&vendor_guid, psetvariable->VendorGuid,
>>> +                            sizeof(EFI_GUID)))
>>> +            return -EFAULT;
>>> +
>>> +        convert_from_guid(&vendor, &vendor_guid);
>>> +        status = efi.set_variable(psetvariable->VariableName, &vendor,
>>> +                    attr, datasize, psetvariable->Data);
>>> +        return status;
>>> +
>>> +    case EFI_RUNTIME_GET_TIME:
>>> +        status = efi.get_time(&eft, &cap);
>>> +        if (status != EFI_SUCCESS) {
>>> +            printk(KERN_ERR "efitime: can't read time\n");
>>> +            return status;
>>> +        }
>>> +
>>> +        pgettime = (struct efi_gettime __user *)arg;
>>> +        if (put_user(cap.resolution,
>>> +                    &pgettime->Capabilities->Resolution) ||
>>> +                    put_user(cap.accuracy,
>>> +                    &pgettime->Capabilities->Accuracy) ||
>>> +                    put_user(cap.sets_to_zero,
>>> +                    &pgettime->Capabilities->SetsToZero))
>>> +            return -EFAULT;
>>> +        return copy_to_user(pgettime->Time, &eft,
>>> +                sizeof(EFI_TIME)) ? -EFAULT : status;
>>> +
>>> +    case EFI_RUNTIME_SET_TIME:
>>> +
>>> +        psettime = (struct efi_settime __user *)arg;
>>> +        if (copy_from_user(&efi_time, psettime->Time,
>>> +                        sizeof(EFI_TIME)))
>>> +            return -EFAULT;
>>> +        convert_to_efi_time(&eft, &efi_time);
>>> +        status = efi.set_time(&eft);
>>> +        return status == EFI_SUCCESS ? status : -EINVAL;
>>> +
>>> +    case EFI_RUNTIME_GET_WAKETIME:
>>> +
>>> +        status = efi.get_wakeup_time((efi_bool_t *)&enabled,
>>> +                        (efi_bool_t *)&pending, &eft);
>>> +
>>> +        if (status != EFI_SUCCESS)
>>> +            return status;
>>> +
>>> +        pgetwakeuptime = (struct efi_getwakeuptime __user *)arg;
>>> +
>>> +        if (put_user(enabled, pgetwakeuptime->Enabled) ||
>>> +                put_user(pending, pgetwakeuptime->Pending))
>>> +            return -EFAULT;
>>> +
>>> +        convert_from_efi_time(&eft, &efi_time);
>>> +
>>> +        return copy_to_user(pgetwakeuptime->Time, &efi_time,
>>> +                sizeof(EFI_TIME)) ? -EFAULT : status;
>>> +
>>> +    case EFI_RUNTIME_SET_WAKETIME:
>>> +
>>> +        psetwakeuptime = (struct efi_setwakeuptime __user *)arg;
>>> +
>>> +        if (get_user(enabled, &psetwakeuptime->Enabled) ||
>>> +                    copy_from_user(&efi_time,
>>> +                    psetwakeuptime->Time,
>>> +                    sizeof(EFI_TIME)))
>>> +            return -EFAULT;
>>> +
>>> +        convert_to_efi_time(&eft, &efi_time);
>>> +
>>> +        status = efi.set_wakeup_time(enabled, &eft);
>>> +
>>> +        return status == EFI_SUCCESS ? status : -EINVAL;
>>> +
>>> +    case EFI_RUNTIME_GET_NEXTVARIABLENAME:
>>> +
>>> +        pgetnextvariablename = (struct efi_getnextvariablename
>>> +                                __user *)arg;
>>> +
>>> +        if (get_user(name_size, pgetnextvariablename->VariableNameSize)
>>> +                || copy_from_user(&vendor_guid,
>>> +                    pgetnextvariablename->VendorGuid,
>>> +                    sizeof(EFI_GUID)))
>>> +            return -EFAULT;
>>> +        if (name_size > 1024)
>>> +            return -EFAULT;
>>> +
>>> +        convert_from_guid(&vendor, &vendor_guid);
>>> +
>>> +        status = efi.get_next_variable(&name_size,
>>> +                    pgetnextvariablename->VariableName,
>>> +                                &vendor);
>>> +
>>> +        if (status != EFI_SUCCESS)
>>> +            return status;
>>> +        convert_to_guid(&vendor, &vendor_guid);
>>> +
>>> +        if (put_user(name_size,
>>> pgetnextvariablename->VariableNameSize))
>>> +            return -EFAULT;
>>> +
>>> +        if (copy_to_user(pgetnextvariablename->VendorGuid,
>>> +                        &vendor_guid, sizeof(EFI_GUID)))
>>> +            return -EFAULT;
>>> +        return status;
>>> +    }
>>> +
>>> +    return -ENOTTY;
>>> +}
>>
>>
>> OK, so efi_runtime_ioctl() returns a signed long, but the code is
>> actually returning status which is an efi_status which is an unsigned
>> long.  What happens if the efi status has the top bit set? .. this would
>> return a -ve value which looks like an error.  I think we need to see if
>> this makes sense or not - what is the range of return values from
>> underling EFI calls?
>>
>>
>
> yup, I noticed this as well, actually, this is a temporary solution.

Yep, I understand that, which is understandable.  However, temporary 
solutions turn into fixed implementations which are hard to change, so 
my preference is to do it right first time.

> The high bit of return value means EFI_STATUS Success Codes (High Bit Clear)
> or EFI_STATUS Warning Codes (High Bit Clear), I ignore the high bit
> here. So if we get the status in user space, we get two possibilities
> (error or warning).

OK - so returning the high bit will confuse the ioctl() return as this 
does indicate an error.


> I am planing to put the efi_status into each structures and return to
> user space. Is that make sense to you? or any suggestion? :)
>

Yes, indeed, that makes sense.

Apologies if it means more work. :-/

Colin

>>> +
>>> +static int efi_runtime_open(struct inode *inode, struct file *file)
>>> +{
>>> +    /*
>>> +     * nothing special to do here
>>> +     * We do accept multiple open files at the same time as we
>>> +     * synchronize on the per call operation.
>>> +     */
>>> +    return 0;
>>> +}
>>> +
>>> +static int efi_runtime_close(struct inode *inode, struct file *file)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +/*
>>> + *    The various file operations we support.
>>> + */
>>> +static const struct file_operations efi_runtime_fops = {
>>> +    .owner        = THIS_MODULE,
>>> +    .unlocked_ioctl    = efi_runtime_ioctl,
>>> +    .open        = efi_runtime_open,
>>> +    .release    = efi_runtime_close,
>>> +    .llseek        = no_llseek,
>>> +};
>>> +
>>> +static struct miscdevice efi_runtime_dev = {
>>> +    MISC_DYNAMIC_MINOR,
>>> +    "efi_runtime",
>>> +    &efi_runtime_fops
>>> +};
>>> +
>>> +static int __init efi_runtime_init(void)
>>> +{
>>> +    int ret;
>>> +
>>> +    printk(KERN_INFO "EFI_RUNTIME Driver v%s\n", EFI_FWTS_EFI_VERSION);
>>> +
>>> +    ret = misc_register(&efi_runtime_dev);
>>> +    if (ret) {
>>> +        printk(KERN_ERR "efi_runtime: can't misc_register on
>>> minor=%d\n",
>>> +                MISC_DYNAMIC_MINOR);
>>> +        return ret;
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static void __exit efi_runtime_exit(void)
>>> +{
>>> +    printk(KERN_INFO "EFI_RUNTIME Driver Exit.\n");
>>> +    misc_deregister(&efi_runtime_dev);
>>> +}
>>> +
>>> +module_init(efi_runtime_init);
>>> +module_exit(efi_runtime_exit);
>>> +
>>> diff --git a/efi_runtime/efi_runtime.h b/efi_runtime/efi_runtime.h
>>> new file mode 100644
>>> index 0000000..0766916
>>> --- /dev/null
>>> +++ b/efi_runtime/efi_runtime.h
>>> @@ -0,0 +1,112 @@
>>> +/*
>>> + * EFI Runtime driver
>>> + *
>>> + * Copyright(C) 2012 Canonical Ltd.
>>> + *
>>> + *  This program is free software; you can redistribute it and/or
>>> modify
>>> + *  it under the terms of the GNU General Public License as
>>> published by
>>> + *  the Free Software Foundation; either version 2 of the License, or
>>> + *  (at your option) any later version.
>>> + *
>>> + *  This program is distributed in the hope that it will be useful,
>>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + *  GNU General Public License for more details.
>>> + *
>>> + *  You should have received a copy of the GNU General Public License
>>> + *  along with this program; if not, write to the Free Software
>>> + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
>>> 02111-1307  USA
>>> + */
>>> +
>>> +#ifndef _EFI_RUNTIME_H_
>>> +#define _EFI_RUNTIME_H_
>>> +
>>> +typedef struct {
>>> +    uint32_t    Data1;
>>> +    uint16_t    Data2;
>>> +    uint16_t    Data3;
>>> +    uint8_t        Data4[8];
>>> +} __attribute__ ((packed)) EFI_GUID;
>>> +
>>> +typedef struct {
>>> +    uint16_t    Year;        /* 1900 – 9999 */
>>> +    uint8_t        Month;        /* 1 – 12 */
>>> +    uint8_t        Day;        /* 1 – 31 */
>>> +    uint8_t        Hour;        /* 0 – 23 */
>>> +    uint8_t        Minute;        /* 0 – 59 */
>>> +    uint8_t        Second;        /* 0 – 59 */
>>> +    uint8_t        Pad1;
>>> +    uint32_t    Nanosecond;    /* 0 – 999,999,999 */
>>> +    int16_t        TimeZone;    /* -1440 to 1440 or 2047 */
>>> +    uint8_t        Daylight;
>>> +    uint8_t        Pad2;
>>> +} __attribute__ ((packed)) EFI_TIME;
>>> +
>>> +typedef struct {
>>> +    uint32_t    Resolution;
>>> +    uint32_t    Accuracy;
>>> +    uint8_t        SetsToZero;
>>> +} __attribute__ ((packed)) EFI_TIME_CAPABILITIES;
>>> +
>>> +struct efi_getvariable {
>>> +    uint16_t    *VariableName;
>>> +    EFI_GUID    *VendorGuid;
>>> +    uint32_t    *Attributes;
>>> +    uint64_t    *DataSize;
>>> +    void        *Data;
>>> +} __attribute__ ((packed));
>>> +
>>> +struct efi_setvariable {
>>> +    uint16_t    *VariableName;
>>> +    EFI_GUID    *VendorGuid;
>>> +    uint32_t    Attributes;
>>> +    uint64_t    DataSize;
>>> +    void        *Data;
>>> +} __attribute__ ((packed));
>>> +
>>> +struct efi_getnextvariablename {
>>> +    uint64_t    *VariableNameSize;
>>> +    uint16_t    *VariableName;
>>> +    EFI_GUID    *VendorGuid;
>>> +} __attribute__ ((packed));
>>> +
>>> +struct efi_gettime {
>>> +    EFI_TIME        *Time;
>>> +    EFI_TIME_CAPABILITIES    *Capabilities;
>>> +} __attribute__ ((packed));
>>> +
>>> +struct efi_settime {
>>> +    EFI_TIME        *Time;
>>> +} __attribute__ ((packed));
>>> +
>>> +struct efi_getwakeuptime {
>>> +    uint8_t        *Enabled;
>>> +    uint8_t        *Pending;
>>> +    EFI_TIME    *Time;
>>> +} __attribute__ ((packed));
>>> +
>>> +struct efi_setwakeuptime {
>>> +    uint8_t        Enabled;
>>> +    EFI_TIME    *Time;
>>> +} __attribute__ ((packed));
>>> +
>>> +/* ioctl calls that are permitted to the /dev/efi_runtime interface. */
>>> +#define EFI_RUNTIME_GET_VARIABLE \
>>> +    _IOWR('p', 0x01, struct efi_getvariable)
>>> +#define EFI_RUNTIME_SET_VARIABLE \
>>> +    _IOW('p', 0x02, struct efi_setvariable)
>>> +
>>> +#define EFI_RUNTIME_GET_TIME \
>>> +    _IOR('p', 0x03, struct efi_gettime)
>>> +#define EFI_RUNTIME_SET_TIME \
>>> +    _IOW('p', 0x04, struct efi_settime)
>>> +
>>> +#define EFI_RUNTIME_GET_WAKETIME \
>>> +    _IOR('p', 0x05, struct efi_getwakeuptime)
>>> +#define EFI_RUNTIME_SET_WAKETIME \
>>> +    _IOW('p', 0x06, struct efi_setwakeuptime)
>>> +
>>> +#define EFI_RUNTIME_GET_NEXTVARIABLENAME \
>>> +    _IOWR('p', 0x07, struct efi_getnextvariablename)
>>> +
>>> +#endif /* _EFI_RUNTIME_H_ */
>>>
>>
>>
>
diff mbox

Patch

diff --git a/efi_runtime/Makefile b/efi_runtime/Makefile
new file mode 100644
index 0000000..8ed7dea
--- /dev/null
+++ b/efi_runtime/Makefile
@@ -0,0 +1,6 @@ 
+obj-m += efi_runtime.o
+all:
+	make -C /lib/modules/`uname -r`/build M=`pwd` modules
+
+clean:
+	make -C /lib/modules/`uname -r`/build M=`pwd` clean
diff --git a/efi_runtime/efi_runtime.c b/efi_runtime/efi_runtime.c
new file mode 100644
index 0000000..901af42
--- /dev/null
+++ b/efi_runtime/efi_runtime.c
@@ -0,0 +1,310 @@ 
+/*
+ * EFI Runtime driver
+ *
+ * Copyright(C) 2012 Canonical Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/efi.h>
+
+#include <linux/uaccess.h>
+
+#include "efi_runtime.h"
+
+#define EFI_FWTS_EFI_VERSION	"0.1"
+
+MODULE_AUTHOR("Ivan Hu");
+MODULE_DESCRIPTION("EFI Runtime Driver");
+MODULE_LICENSE("GPL");
+
+static void convert_from_efi_time(efi_time_t *eft, EFI_TIME *time)
+{
+	memset(time, 0, sizeof(EFI_TIME));
+	time->Year = eft->year;
+	time->Month = eft->month;
+	time->Day  = eft->day;
+	time->Hour = eft->hour;
+	time->Minute = eft->minute;
+	time->Second  = eft->second;
+	time->Pad1 = eft->pad1;
+	time->Nanosecond = eft->nanosecond;
+	time->TimeZone = eft->timezone;
+	time->Daylight = eft->daylight;
+	time->Pad2 = eft->pad2;
+}
+
+static void convert_to_efi_time(efi_time_t *eft, EFI_TIME *time)
+{
+	memset(eft, 0, sizeof(eft));
+	eft->year = time->Year;
+	eft->month = time->Month;
+	eft->day = time->Day;
+	eft->hour = time->Hour;
+	eft->minute = time->Minute;
+	eft->second = time->Second;
+	eft->pad1 = time->Pad1;
+	eft->nanosecond = time->Nanosecond;
+	eft->timezone = time->TimeZone;
+	eft->daylight = time->Daylight;
+	eft->pad2 = time->Pad2;
+}
+
+static void convert_from_guid(efi_guid_t *vendor, EFI_GUID *vendor_guid)
+{
+	int i;
+	for (i = 0; i < 16; i++) {
+		if (i < 4)
+			vendor->b[i] = (vendor_guid->Data1 >> (8*i)) & 0xff;
+		else if (i < 6)
+			vendor->b[i] = (vendor_guid->Data2 >> (8*(i-4))) & 0xff;
+		else if (i < 8)
+			vendor->b[i] = (vendor_guid->Data3 >> (8*(i-6))) & 0xff;
+		else
+			vendor->b[i] = (vendor_guid->Data4[i-8]);
+	}
+}
+
+static void convert_to_guid(efi_guid_t *vendor, EFI_GUID *vendor_guid)
+{
+	int i;
+	vendor_guid->Data1 = vendor->b[0] + (vendor->b[1] << 8) +
+				(vendor->b[2] << 16) + (vendor->b[3] << 24);
+	vendor_guid->Data2 = vendor->b[4] + (vendor->b[5] << 8);
+	vendor_guid->Data3 = vendor->b[6] + (vendor->b[7] << 8);
+	for (i = 0; i < 8; i++)
+		vendor_guid->Data4[i] = vendor->b[i+8];
+}
+
+static long efi_runtime_ioctl(struct file *file, unsigned int cmd,
+							unsigned long arg)
+{
+	efi_status_t status;
+	struct efi_getvariable __user *pgetvariable;
+	struct efi_setvariable __user *psetvariable;
+
+	efi_guid_t vendor;
+	EFI_GUID vendor_guid;
+	unsigned long datasize;
+	uint32_t attr;
+
+	efi_time_t eft;
+	efi_time_cap_t cap;
+	struct efi_gettime __user *pgettime;
+	struct efi_settime __user *psettime;
+
+	unsigned char enabled, pending;
+	EFI_TIME efi_time;
+	struct efi_getwakeuptime __user *pgetwakeuptime;
+	struct efi_setwakeuptime __user *psetwakeuptime;
+
+	struct efi_getnextvariablename __user *pgetnextvariablename;
+	unsigned long name_size;
+
+	switch (cmd) {
+	case EFI_RUNTIME_GET_VARIABLE:
+		pgetvariable = (struct efi_getvariable __user *)arg;
+
+		if (get_user(datasize, pgetvariable->DataSize) ||
+			copy_from_user(&vendor_guid, pgetvariable->VendorGuid,
+							sizeof(EFI_GUID)))
+			return -EFAULT;
+
+		convert_from_guid(&vendor, &vendor_guid);
+		status = efi.get_variable(pgetvariable->VariableName, &vendor,
+					&attr, &datasize, pgetvariable->Data);
+
+		if (status == EFI_SUCCESS) {
+			if (put_user(attr, pgetvariable->Attributes) ||
+				put_user(datasize, pgetvariable->DataSize))
+				return -EFAULT;
+			return status;
+		} else {
+			printk(KERN_ERR "efi_runtime: can't get variable\n");
+			return status;
+		}
+
+	case EFI_RUNTIME_SET_VARIABLE:
+		psetvariable = (struct efi_setvariable __user *)arg;
+		if (get_user(datasize, &psetvariable->DataSize) ||
+			get_user(attr, &psetvariable->Attributes) ||
+			copy_from_user(&vendor_guid, psetvariable->VendorGuid,
+							sizeof(EFI_GUID)))
+			return -EFAULT;
+
+		convert_from_guid(&vendor, &vendor_guid);
+		status = efi.set_variable(psetvariable->VariableName, &vendor,
+					attr, datasize, psetvariable->Data);
+		return status;
+
+	case EFI_RUNTIME_GET_TIME:
+		status = efi.get_time(&eft, &cap);
+		if (status != EFI_SUCCESS) {
+			printk(KERN_ERR "efitime: can't read time\n");
+			return status;
+		}
+
+		pgettime = (struct efi_gettime __user *)arg;
+		if (put_user(cap.resolution,
+					&pgettime->Capabilities->Resolution) ||
+					put_user(cap.accuracy,
+					&pgettime->Capabilities->Accuracy) ||
+					put_user(cap.sets_to_zero,
+					&pgettime->Capabilities->SetsToZero))
+			return -EFAULT;
+		return copy_to_user(pgettime->Time, &eft,
+				sizeof(EFI_TIME)) ? -EFAULT : status;
+
+	case EFI_RUNTIME_SET_TIME:
+
+		psettime = (struct efi_settime __user *)arg;
+		if (copy_from_user(&efi_time, psettime->Time,
+						sizeof(EFI_TIME)))
+			return -EFAULT;
+		convert_to_efi_time(&eft, &efi_time);
+		status = efi.set_time(&eft);
+		return status == EFI_SUCCESS ? status : -EINVAL;
+
+	case EFI_RUNTIME_GET_WAKETIME:
+
+		status = efi.get_wakeup_time((efi_bool_t *)&enabled,
+						(efi_bool_t *)&pending, &eft);
+
+		if (status != EFI_SUCCESS)
+			return status;
+
+		pgetwakeuptime = (struct efi_getwakeuptime __user *)arg;
+
+		if (put_user(enabled, pgetwakeuptime->Enabled) ||
+				put_user(pending, pgetwakeuptime->Pending))
+			return -EFAULT;
+
+		convert_from_efi_time(&eft, &efi_time);
+
+		return copy_to_user(pgetwakeuptime->Time, &efi_time,
+				sizeof(EFI_TIME)) ? -EFAULT : status;
+
+	case EFI_RUNTIME_SET_WAKETIME:
+
+		psetwakeuptime = (struct efi_setwakeuptime __user *)arg;
+
+		if (get_user(enabled, &psetwakeuptime->Enabled) ||
+					copy_from_user(&efi_time,
+					psetwakeuptime->Time,
+					sizeof(EFI_TIME)))
+			return -EFAULT;
+
+		convert_to_efi_time(&eft, &efi_time);
+
+		status = efi.set_wakeup_time(enabled, &eft);
+
+		return status == EFI_SUCCESS ? status : -EINVAL;
+
+	case EFI_RUNTIME_GET_NEXTVARIABLENAME:
+
+		pgetnextvariablename = (struct efi_getnextvariablename
+								__user *)arg;
+
+		if (get_user(name_size, pgetnextvariablename->VariableNameSize)
+				|| copy_from_user(&vendor_guid,
+					pgetnextvariablename->VendorGuid,
+					sizeof(EFI_GUID)))
+			return -EFAULT;
+		if (name_size > 1024)
+			return -EFAULT;
+
+		convert_from_guid(&vendor, &vendor_guid);
+
+		status = efi.get_next_variable(&name_size,
+					pgetnextvariablename->VariableName,
+								&vendor);
+
+		if (status != EFI_SUCCESS)
+			return status;
+		convert_to_guid(&vendor, &vendor_guid);
+
+		if (put_user(name_size, pgetnextvariablename->VariableNameSize))
+			return -EFAULT;
+
+		if (copy_to_user(pgetnextvariablename->VendorGuid,
+						&vendor_guid, sizeof(EFI_GUID)))
+			return -EFAULT;
+		return status;
+	}
+
+	return -ENOTTY;
+}
+
+static int efi_runtime_open(struct inode *inode, struct file *file)
+{
+	/*
+	 * nothing special to do here
+	 * We do accept multiple open files at the same time as we
+	 * synchronize on the per call operation.
+	 */
+	return 0;
+}
+
+static int efi_runtime_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+static const struct file_operations efi_runtime_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= efi_runtime_ioctl,
+	.open		= efi_runtime_open,
+	.release	= efi_runtime_close,
+	.llseek		= no_llseek,
+};
+
+static struct miscdevice efi_runtime_dev = {
+	MISC_DYNAMIC_MINOR,
+	"efi_runtime",
+	&efi_runtime_fops
+};
+
+static int __init efi_runtime_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "EFI_RUNTIME Driver v%s\n", EFI_FWTS_EFI_VERSION);
+
+	ret = misc_register(&efi_runtime_dev);
+	if (ret) {
+		printk(KERN_ERR "efi_runtime: can't misc_register on minor=%d\n",
+				MISC_DYNAMIC_MINOR);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit efi_runtime_exit(void)
+{
+	printk(KERN_INFO "EFI_RUNTIME Driver Exit.\n");
+	misc_deregister(&efi_runtime_dev);
+}
+
+module_init(efi_runtime_init);
+module_exit(efi_runtime_exit);
+
diff --git a/efi_runtime/efi_runtime.h b/efi_runtime/efi_runtime.h
new file mode 100644
index 0000000..0766916
--- /dev/null
+++ b/efi_runtime/efi_runtime.h
@@ -0,0 +1,112 @@ 
+/*
+ * EFI Runtime driver
+ *
+ * Copyright(C) 2012 Canonical Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _EFI_RUNTIME_H_
+#define _EFI_RUNTIME_H_
+
+typedef struct {
+	uint32_t	Data1;
+	uint16_t	Data2;
+	uint16_t	Data3;
+	uint8_t		Data4[8];
+} __attribute__ ((packed)) EFI_GUID;
+
+typedef struct {
+	uint16_t	Year;		/* 1900 – 9999 */
+	uint8_t		Month;		/* 1 – 12 */
+	uint8_t		Day;		/* 1 – 31 */
+	uint8_t		Hour;		/* 0 – 23 */
+	uint8_t		Minute;		/* 0 – 59 */
+	uint8_t		Second;		/* 0 – 59 */
+	uint8_t		Pad1;
+	uint32_t	Nanosecond;	/* 0 – 999,999,999 */
+	int16_t		TimeZone;	/* -1440 to 1440 or 2047 */
+	uint8_t		Daylight;
+	uint8_t		Pad2;
+} __attribute__ ((packed)) EFI_TIME;
+
+typedef struct {
+	uint32_t	Resolution;
+	uint32_t	Accuracy;
+	uint8_t		SetsToZero;
+} __attribute__ ((packed)) EFI_TIME_CAPABILITIES;
+
+struct efi_getvariable {
+	uint16_t	*VariableName;
+	EFI_GUID	*VendorGuid;
+	uint32_t	*Attributes;
+	uint64_t	*DataSize;
+	void		*Data;
+} __attribute__ ((packed));
+
+struct efi_setvariable {
+	uint16_t	*VariableName;
+	EFI_GUID	*VendorGuid;
+	uint32_t	Attributes;
+	uint64_t	DataSize;
+	void		*Data;
+} __attribute__ ((packed));
+
+struct efi_getnextvariablename {
+	uint64_t	*VariableNameSize;
+	uint16_t	*VariableName;
+	EFI_GUID	*VendorGuid;
+} __attribute__ ((packed));
+
+struct efi_gettime {
+	EFI_TIME		*Time;
+	EFI_TIME_CAPABILITIES	*Capabilities;
+} __attribute__ ((packed));
+
+struct efi_settime {
+	EFI_TIME		*Time;
+} __attribute__ ((packed));
+
+struct efi_getwakeuptime {
+	uint8_t		*Enabled;
+	uint8_t		*Pending;
+	EFI_TIME	*Time;
+} __attribute__ ((packed));
+
+struct efi_setwakeuptime {
+	uint8_t		Enabled;
+	EFI_TIME	*Time;
+} __attribute__ ((packed));
+
+/* ioctl calls that are permitted to the /dev/efi_runtime interface. */
+#define EFI_RUNTIME_GET_VARIABLE \
+	_IOWR('p', 0x01, struct efi_getvariable)
+#define EFI_RUNTIME_SET_VARIABLE \
+	_IOW('p', 0x02, struct efi_setvariable)
+
+#define EFI_RUNTIME_GET_TIME \
+	_IOR('p', 0x03, struct efi_gettime)
+#define EFI_RUNTIME_SET_TIME \
+	_IOW('p', 0x04, struct efi_settime)
+
+#define EFI_RUNTIME_GET_WAKETIME \
+	_IOR('p', 0x05, struct efi_getwakeuptime)
+#define EFI_RUNTIME_SET_WAKETIME \
+	_IOW('p', 0x06, struct efi_setwakeuptime)
+
+#define EFI_RUNTIME_GET_NEXTVARIABLENAME \
+	_IOWR('p', 0x07, struct efi_getnextvariablename)
+
+#endif /* _EFI_RUNTIME_H_ */