Message ID | 1348218880-14960-1-git-send-email-ivan.hu@canonical.com |
---|---|
State | Accepted |
Headers | show |
On 21/09/12 10:14, 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 | 325 +++++++++++++++++++++++++++++++++++++++++++++ > efi_runtime/efi_runtime.h | 119 +++++++++++++++++ > 3 files changed, 450 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..7d99fbc > --- /dev/null > +++ b/efi_runtime/efi_runtime.c > @@ -0,0 +1,325 @@ > +/* > + * 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 (put_user(status, pgetvariable->status)) > + return -EFAULT; > + if (status == EFI_SUCCESS) { > + if (put_user(attr, pgetvariable->Attributes) || > + put_user(datasize, pgetvariable->DataSize)) > + return -EFAULT; > + return 0; > + } else { > + printk(KERN_ERR "efi_runtime: can't get variable\n"); > + return -EINVAL; > + } > + > + 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); > + > + if (put_user(status, psetvariable->status)) > + return -EFAULT; > + return status == EFI_SUCCESS ? 0 : -EINVAL; > + > + case EFI_RUNTIME_GET_TIME: > + status = efi.get_time(&eft, &cap); > + pgettime = (struct efi_gettime __user *)arg; > + if (put_user(status, pgettime->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) { > + printk(KERN_ERR "efitime: can't read time\n"); > + return -EINVAL; > + } > + 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 : 0; > + > + 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); > + > + if (put_user(status, psettime->status)) > + return -EFAULT; > + > + return status == EFI_SUCCESS ? 0 : -EINVAL; > + > + case EFI_RUNTIME_GET_WAKETIME: > + > + status = efi.get_wakeup_time((efi_bool_t *)&enabled, > + (efi_bool_t *)&pending, &eft); > + > + pgetwakeuptime = (struct efi_getwakeuptime __user *)arg; > + > + if (put_user(status, pgetwakeuptime->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) > + return -EINVAL; > + > + 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 : 0; > + > + 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); > + > + if (put_user(status, psetwakeuptime->status)) > + return -EFAULT; > + > + return status == EFI_SUCCESS ? 0 : -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 (put_user(status, pgetnextvariablename->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) > + return -EINVAL; > + 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 0; > + } > + > + 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..7387406 > --- /dev/null > +++ b/efi_runtime/efi_runtime.h > @@ -0,0 +1,119 @@ > +/* > + * 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; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_setvariable { > + uint16_t *VariableName; > + EFI_GUID *VendorGuid; > + uint32_t Attributes; > + uint64_t DataSize; > + void *Data; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_getnextvariablename { > + uint64_t *VariableNameSize; > + uint16_t *VariableName; > + EFI_GUID *VendorGuid; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_gettime { > + EFI_TIME *Time; > + EFI_TIME_CAPABILITIES *Capabilities; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_settime { > + EFI_TIME *Time; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_getwakeuptime { > + uint8_t *Enabled; > + uint8_t *Pending; > + EFI_TIME *Time; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_setwakeuptime { > + uint8_t Enabled; > + EFI_TIME *Time; > + uint64_t *status; > +} __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_ */ > Many thanks Ivan. Let's get this into fwts and we can get the ball rolling on this. Colin
On Fri, Sep 21, 2012 at 5:14 PM, Ivan Hu <ivan.hu@canonical.com> 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 | 325 +++++++++++++++++++++++++++++++++++++++++++++ > efi_runtime/efi_runtime.h | 119 +++++++++++++++++ > 3 files changed, 450 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..7d99fbc > --- /dev/null > +++ b/efi_runtime/efi_runtime.c > @@ -0,0 +1,325 @@ > +/* > + * 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 (put_user(status, pgetvariable->status)) > + return -EFAULT; > + if (status == EFI_SUCCESS) { > + if (put_user(attr, pgetvariable->Attributes) || > + put_user(datasize, pgetvariable->DataSize)) > + return -EFAULT; > + return 0; > + } else { > + printk(KERN_ERR "efi_runtime: can't get variable\n"); > + return -EINVAL; > + } > + > + 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); > + > + if (put_user(status, psetvariable->status)) > + return -EFAULT; > + return status == EFI_SUCCESS ? 0 : -EINVAL; > + > + case EFI_RUNTIME_GET_TIME: > + status = efi.get_time(&eft, &cap); > + pgettime = (struct efi_gettime __user *)arg; > + if (put_user(status, pgettime->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) { > + printk(KERN_ERR "efitime: can't read time\n"); > + return -EINVAL; > + } > + 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 : 0; > + > + 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); > + > + if (put_user(status, psettime->status)) > + return -EFAULT; > + > + return status == EFI_SUCCESS ? 0 : -EINVAL; > + > + case EFI_RUNTIME_GET_WAKETIME: > + > + status = efi.get_wakeup_time((efi_bool_t *)&enabled, > + (efi_bool_t *)&pending, &eft); > + > + pgetwakeuptime = (struct efi_getwakeuptime __user *)arg; > + > + if (put_user(status, pgetwakeuptime->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) > + return -EINVAL; > + > + 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 : 0; > + > + 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); > + > + if (put_user(status, psetwakeuptime->status)) > + return -EFAULT; > + > + return status == EFI_SUCCESS ? 0 : -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 (put_user(status, pgetnextvariablename->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) > + return -EINVAL; > + 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 0; > + } > + > + 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..7387406 > --- /dev/null > +++ b/efi_runtime/efi_runtime.h > @@ -0,0 +1,119 @@ > +/* > + * 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; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_setvariable { > + uint16_t *VariableName; > + EFI_GUID *VendorGuid; > + uint32_t Attributes; > + uint64_t DataSize; > + void *Data; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_getnextvariablename { > + uint64_t *VariableNameSize; > + uint16_t *VariableName; > + EFI_GUID *VendorGuid; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_gettime { > + EFI_TIME *Time; > + EFI_TIME_CAPABILITIES *Capabilities; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_settime { > + EFI_TIME *Time; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_getwakeuptime { > + uint8_t *Enabled; > + uint8_t *Pending; > + EFI_TIME *Time; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_setwakeuptime { > + uint8_t Enabled; > + EFI_TIME *Time; > + uint64_t *status; > +} __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_ */ > -- > 1.7.9.5 > Thanks for the patch. :-) Acked-by: Keng-Yu Lin <kengyu@canonical.com>
On 09/21/2012 05:14 PM, 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 | 325 +++++++++++++++++++++++++++++++++++++++++++++ > efi_runtime/efi_runtime.h | 119 +++++++++++++++++ > 3 files changed, 450 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..7d99fbc > --- /dev/null > +++ b/efi_runtime/efi_runtime.c > @@ -0,0 +1,325 @@ > +/* > + * 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 (put_user(status, pgetvariable->status)) > + return -EFAULT; > + if (status == EFI_SUCCESS) { > + if (put_user(attr, pgetvariable->Attributes) || > + put_user(datasize, pgetvariable->DataSize)) > + return -EFAULT; > + return 0; > + } else { > + printk(KERN_ERR "efi_runtime: can't get variable\n"); > + return -EINVAL; > + } > + > + 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); > + > + if (put_user(status, psetvariable->status)) > + return -EFAULT; > + return status == EFI_SUCCESS ? 0 : -EINVAL; > + > + case EFI_RUNTIME_GET_TIME: > + status = efi.get_time(&eft, &cap); > + pgettime = (struct efi_gettime __user *)arg; > + if (put_user(status, pgettime->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) { > + printk(KERN_ERR "efitime: can't read time\n"); > + return -EINVAL; > + } > + 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 : 0; > + > + 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); > + > + if (put_user(status, psettime->status)) > + return -EFAULT; > + > + return status == EFI_SUCCESS ? 0 : -EINVAL; > + > + case EFI_RUNTIME_GET_WAKETIME: > + > + status = efi.get_wakeup_time((efi_bool_t *)&enabled, > + (efi_bool_t *)&pending, &eft); > + > + pgetwakeuptime = (struct efi_getwakeuptime __user *)arg; > + > + if (put_user(status, pgetwakeuptime->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) > + return -EINVAL; > + > + 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 : 0; > + > + 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); > + > + if (put_user(status, psetwakeuptime->status)) > + return -EFAULT; > + > + return status == EFI_SUCCESS ? 0 : -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 (put_user(status, pgetnextvariablename->status)) > + return -EFAULT; > + if (status != EFI_SUCCESS) > + return -EINVAL; > + 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 0; > + } > + > + 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..7387406 > --- /dev/null > +++ b/efi_runtime/efi_runtime.h > @@ -0,0 +1,119 @@ > +/* > + * 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; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_setvariable { > + uint16_t *VariableName; > + EFI_GUID *VendorGuid; > + uint32_t Attributes; > + uint64_t DataSize; > + void *Data; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_getnextvariablename { > + uint64_t *VariableNameSize; > + uint16_t *VariableName; > + EFI_GUID *VendorGuid; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_gettime { > + EFI_TIME *Time; > + EFI_TIME_CAPABILITIES *Capabilities; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_settime { > + EFI_TIME *Time; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_getwakeuptime { > + uint8_t *Enabled; > + uint8_t *Pending; > + EFI_TIME *Time; > + uint64_t *status; > +} __attribute__ ((packed)); > + > +struct efi_setwakeuptime { > + uint8_t Enabled; > + EFI_TIME *Time; > + uint64_t *status; > +} __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_ */ > Acked-by: Alex Hung <alex.hung@canonical.com>
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..7d99fbc --- /dev/null +++ b/efi_runtime/efi_runtime.c @@ -0,0 +1,325 @@ +/* + * 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 (put_user(status, pgetvariable->status)) + return -EFAULT; + if (status == EFI_SUCCESS) { + if (put_user(attr, pgetvariable->Attributes) || + put_user(datasize, pgetvariable->DataSize)) + return -EFAULT; + return 0; + } else { + printk(KERN_ERR "efi_runtime: can't get variable\n"); + return -EINVAL; + } + + 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); + + if (put_user(status, psetvariable->status)) + return -EFAULT; + return status == EFI_SUCCESS ? 0 : -EINVAL; + + case EFI_RUNTIME_GET_TIME: + status = efi.get_time(&eft, &cap); + pgettime = (struct efi_gettime __user *)arg; + if (put_user(status, pgettime->status)) + return -EFAULT; + if (status != EFI_SUCCESS) { + printk(KERN_ERR "efitime: can't read time\n"); + return -EINVAL; + } + 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 : 0; + + 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); + + if (put_user(status, psettime->status)) + return -EFAULT; + + return status == EFI_SUCCESS ? 0 : -EINVAL; + + case EFI_RUNTIME_GET_WAKETIME: + + status = efi.get_wakeup_time((efi_bool_t *)&enabled, + (efi_bool_t *)&pending, &eft); + + pgetwakeuptime = (struct efi_getwakeuptime __user *)arg; + + if (put_user(status, pgetwakeuptime->status)) + return -EFAULT; + if (status != EFI_SUCCESS) + return -EINVAL; + + 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 : 0; + + 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); + + if (put_user(status, psetwakeuptime->status)) + return -EFAULT; + + return status == EFI_SUCCESS ? 0 : -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 (put_user(status, pgetnextvariablename->status)) + return -EFAULT; + if (status != EFI_SUCCESS) + return -EINVAL; + 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 0; + } + + 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..7387406 --- /dev/null +++ b/efi_runtime/efi_runtime.h @@ -0,0 +1,119 @@ +/* + * 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; + uint64_t *status; +} __attribute__ ((packed)); + +struct efi_setvariable { + uint16_t *VariableName; + EFI_GUID *VendorGuid; + uint32_t Attributes; + uint64_t DataSize; + void *Data; + uint64_t *status; +} __attribute__ ((packed)); + +struct efi_getnextvariablename { + uint64_t *VariableNameSize; + uint16_t *VariableName; + EFI_GUID *VendorGuid; + uint64_t *status; +} __attribute__ ((packed)); + +struct efi_gettime { + EFI_TIME *Time; + EFI_TIME_CAPABILITIES *Capabilities; + uint64_t *status; +} __attribute__ ((packed)); + +struct efi_settime { + EFI_TIME *Time; + uint64_t *status; +} __attribute__ ((packed)); + +struct efi_getwakeuptime { + uint8_t *Enabled; + uint8_t *Pending; + EFI_TIME *Time; + uint64_t *status; +} __attribute__ ((packed)); + +struct efi_setwakeuptime { + uint8_t Enabled; + EFI_TIME *Time; + uint64_t *status; +} __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_ */
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 | 325 +++++++++++++++++++++++++++++++++++++++++++++ efi_runtime/efi_runtime.h | 119 +++++++++++++++++ 3 files changed, 450 insertions(+) create mode 100644 efi_runtime/Makefile create mode 100644 efi_runtime/efi_runtime.c create mode 100644 efi_runtime/efi_runtime.h