Message ID | 1350575548-28548-1-git-send-email-ivan.hu@canonical.com |
---|---|
State | Accepted |
Headers | show |
Thanks Ivan On 18/10/12 16:52, Ivan Hu wrote: > Add the set and get time tests of the UEFI runtime service interfaces > which test via efi_runtime driver. > > Signed-off-by: Ivan Hu <ivan.hu@canonical.com> > --- > src/Makefile.am | 5 +- > src/lib/include/fwts_uefi.h | 7 + > src/uefi/uefirttime/uefirttime.c | 328 ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 338 insertions(+), 2 deletions(-) > create mode 100644 src/uefi/uefirttime/uefirttime.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index 6054eb3..b7adc20 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -6,7 +6,7 @@ > # but libfwts.so depends on libraries produced by acpica/source/compiler. > SUBDIRS = acpica/source/compiler lib acpica > > -AM_CPPFLAGS = -I$(top_srcdir)/src/lib/include -I$(top_srcdir)/src/acpica/source/include -Wall -Werror > +AM_CPPFLAGS = -I$(top_srcdir)/src/lib/include -I$(top_srcdir)/src/acpica/source/include -I$(top_srcdir)/efi_runtime -Wall -Werror > > bin_PROGRAMS = fwts > fwts_SOURCES = main.c \ > @@ -66,7 +66,8 @@ fwts_SOURCES = main.c \ > kernel/version/version.c \ > kernel/oops/oops.c \ > uefi/csm/csm.c \ > - uefi/uefidump/uefidump.c > + uefi/uefidump/uefidump.c \ > + uefi/uefirttime/uefirttime.c > > fwts_LDFLAGS = -ljson -lm > > diff --git a/src/lib/include/fwts_uefi.h b/src/lib/include/fwts_uefi.h > index f45027d..73cd773 100644 > --- a/src/lib/include/fwts_uefi.h > +++ b/src/lib/include/fwts_uefi.h > @@ -41,6 +41,13 @@ enum { > FWTS_UEFI_VAR_RUNTIME_ACCESS = 0x00000004 > }; > > +enum { > + FWTS_UEFI_TIME_ADJUST_DAYLIGHT = 0x01, > + FWTS_UEFI_TIME_IN_DAYLIGHT = 0x02 > +}; > + > +#define FWTS_UEFI_UNSPECIFIED_TIMEZONE 0x07FF > + > #if 0 > typedef struct { > char *description; > diff --git a/src/uefi/uefirttime/uefirttime.c b/src/uefi/uefirttime/uefirttime.c > new file mode 100644 > index 0000000..686cf2d > --- /dev/null > +++ b/src/uefi/uefirttime/uefirttime.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright (C) 2012 Canonical > + * > + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > + > +#include <inttypes.h> > +#include <stdio.h> > +#include <stddef.h> > +#include <sys/ioctl.h> > +#include <fcntl.h> > + > +#include "fwts.h" > +#include "fwts_uefi.h" > +#include "efi_runtime.h" > +#include "fwts_efi_module.h" > + > +#define IS_LEAP(year) \ > + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) > + > +static int fd; > +static uint32_t dayofmonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; > + > +static bool dayvalid(EFI_TIME *Time) > +{ > + if (Time->Day < 1) > + return false; > + > + if (Time->Day > dayofmonth[Time->Month - 1]) > + return false; > + > + /* check month 2 */ > + if (Time->Month == 2 && (!IS_LEAP(Time->Year) && Time->Day > 28)) > + return false; > + > + return true; > +} > + > +static bool checktimefields(fwts_framework *fw, EFI_TIME *Time) > +{ > + if (Time->Year < 1900 || Time->Year > 9999) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadYear", > + "Time returned an invalid year %" PRIu16 > + ", should be between 1900 and 9999.", > + Time->Year); > + return false; > + } > + > + if (Time->Month < 1 || Time->Month > 12) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadMonth", > + "Time returned an invalid month %" PRIu8 > + ", should be between 1 and 12.", > + Time->Month); > + return false; > + } > + > + if (!dayvalid(Time)) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadDay", > + "Time returned an invalid day %" PRIu8 > + ", should be between 1 and 28-31 depends on month/year.", > + Time->Day); > + return false; > + } > + > + if (Time->Hour > 23) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadHour", > + "Time returned an invalid hour %" PRIu8 > + ", should be between 0 and 23.", > + Time->Hour); > + return false; > + } > + > + if (Time->Minute > 59) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadMinute", > + "Time returned an invalid minute %" PRIu8 > + ", should be between 0 and 59.", > + Time->Minute); > + return false; > + } > + > + if (Time->Second > 59) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadSecond", > + "Time returned an invalid second %" PRIu8 > + ", should be between 0 and 59.", > + Time->Second); > + return false; > + } > + > + if (Time->Nanosecond > 999999999) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadNanosecond", > + "Time returned an invalid nanosecond %" PRIu32 > + ", should be between 0 and 999999999.", > + Time->Nanosecond); > + return false; > + } > + > + if (!(Time->TimeZone == FWTS_UEFI_UNSPECIFIED_TIMEZONE || > + (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadTimezone", > + "Time returned an invalid timezone %" PRId16 > + ", should be between -1440 and 1440 or 2047.", > + Time->TimeZone); > + return false; > + } > + > + if (Time->Daylight & (~(FWTS_UEFI_TIME_ADJUST_DAYLIGHT | > + FWTS_UEFI_TIME_IN_DAYLIGHT))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadDaylight", > + "Time returned an invalid daylight %" PRIu8 > + ", all other bits except UEFI_TIME_IN_DAYLIGHT and " > + "UEFI_TIME_ADJUST_DAYLIGHT must be zero.", > + Time->Daylight); > + return false; > + } > + return true; > +} > + > +static int uefirttime_init(fwts_framework *fw) > +{ > + if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) { > + fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted."); > + return FWTS_ABORTED; > + } > + > + if (fwts_lib_efi_runtime_load_module(fw) != FWTS_OK) { > + fwts_log_info(fw, "Cannot load efi_runtime module. Aborted."); > + return FWTS_ABORTED; > + } > + > + fd = open("/dev/efi_runtime", O_RDONLY); > + if (fd == -1) { > + fwts_log_info(fw, "Cannot open efi_runtime driver. Aborted."); > + return FWTS_ABORTED; > + } > + > + return FWTS_OK; > +} > + > +static int uefirttime_deinit(fwts_framework *fw) > +{ > + > + close(fd); > + > + return FWTS_OK; > +} > + > + > +static int uefirttime_test1(fwts_framework *fw) > +{ > + long ioret; > + struct efi_gettime gettime; > + EFI_TIME efi_time; > + > + EFI_TIME_CAPABILITIES efi_time_cap; > + uint64_t status; > + > + gettime.Capabilities = &efi_time_cap; > + gettime.Time = &efi_time; > + gettime.status = &status; > + > + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); > + > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", > + "Failed to get time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!checktimefields(fw, gettime.Time)) > + return FWTS_ERROR; > + > + fwts_passed(fw, "UEFI runtime service GetTime interface test passed."); > + > + return FWTS_OK; > +} > + > +static int uefirttime_test2(fwts_framework *fw) > +{ > + > + long ioret; > + struct efi_settime settime; > + uint64_t status; > + struct efi_gettime gettime; > + > + EFI_TIME oldtime; > + EFI_TIME newtime; > + EFI_TIME time; > + EFI_TIME_CAPABILITIES efi_time_cap; > + > + gettime.Capabilities = &efi_time_cap; > + gettime.Time = &oldtime; > + gettime.status = &status; > + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); > + > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", > + "Failed to get time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + /* refer to UEFI SCT 2.3 test items */ > + /* change year */ > + time = oldtime; > + if (time.Year != 2012) > + time.Year = 2012; > + else > + time.Year = 2016; > + > + /* change month */ > + if (time.Month != 1) > + time.Month = 1; > + else > + time.Month = 12; > + > + /* Change daylight */ > + if (time.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT) > + time.Daylight &= ~FWTS_UEFI_TIME_ADJUST_DAYLIGHT; > + else > + time.Daylight |= FWTS_UEFI_TIME_ADJUST_DAYLIGHT; > + > + /* Change time zone */ > + if (time.TimeZone != 0) > + time.TimeZone = 0; > + else > + time.TimeZone = 1; > + > + settime.Time = &time; > + settime.status = &status; > + > + ioret = ioctl(fd, EFI_RUNTIME_SET_TIME, &settime); > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", > + "Failed to set time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + sleep(1); > + > + gettime.Time = &newtime; > + > + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); > + > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", > + "Failed to get time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!((oldtime.Year == 2012) && (newtime.Year == 2016)) && > + !((oldtime.Year != 2012) && (newtime.Year == 2012))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeYear", > + "Failed to set year with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!((oldtime.Month == 1) && (newtime.Month == 12)) && > + !((oldtime.Month != 1) && (newtime.Month == 1))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeMonth", > + "Failed to set month with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!((oldtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT) && > + (!(newtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT))) && > + !((!(oldtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT)) && > + (newtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeDaylight", > + "Failed to set daylight with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!((oldtime.TimeZone == 0) && (newtime.TimeZone == 1)) && > + !((oldtime.TimeZone != 0) && (newtime.TimeZone == 0))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeTimezone", > + "Failed to set timezone with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + /* restore the previous time. */ > + settime.Time = &oldtime; > + ioret = ioctl(fd, EFI_RUNTIME_SET_TIME, &settime); > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", > + "Failed to set time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + fwts_passed(fw, "UEFI runtime service SetTime interface test passed."); > + > + return FWTS_OK; > +} > + > +static fwts_framework_minor_test uefirttime_tests[] = { > + { uefirttime_test1, "Test UEFI RT service get time interface." }, > + { uefirttime_test2, "Test UEFI RT service set time interface." }, > + { NULL, NULL } > +}; > + > +static fwts_framework_ops uefirttime_ops = { > + .description = "UEFI Runtime service time interface tests.", > + .init = uefirttime_init, > + .deinit = uefirttime_deinit, > + .minor_tests = uefirttime_tests > +}; > + > +FWTS_REGISTER(uefirttime, &uefirttime_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UNSAFE | FWTS_FLAG_ROOT_PRIV); > Let's go with this. Nice one. Acked-by: Colin Ian King <colin.king@canonical.com>
On 10/18/2012 11:52 PM, Ivan Hu wrote: > Add the set and get time tests of the UEFI runtime service interfaces > which test via efi_runtime driver. > > Signed-off-by: Ivan Hu <ivan.hu@canonical.com> > --- > src/Makefile.am | 5 +- > src/lib/include/fwts_uefi.h | 7 + > src/uefi/uefirttime/uefirttime.c | 328 ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 338 insertions(+), 2 deletions(-) > create mode 100644 src/uefi/uefirttime/uefirttime.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index 6054eb3..b7adc20 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -6,7 +6,7 @@ > # but libfwts.so depends on libraries produced by acpica/source/compiler. > SUBDIRS = acpica/source/compiler lib acpica > > -AM_CPPFLAGS = -I$(top_srcdir)/src/lib/include -I$(top_srcdir)/src/acpica/source/include -Wall -Werror > +AM_CPPFLAGS = -I$(top_srcdir)/src/lib/include -I$(top_srcdir)/src/acpica/source/include -I$(top_srcdir)/efi_runtime -Wall -Werror > > bin_PROGRAMS = fwts > fwts_SOURCES = main.c \ > @@ -66,7 +66,8 @@ fwts_SOURCES = main.c \ > kernel/version/version.c \ > kernel/oops/oops.c \ > uefi/csm/csm.c \ > - uefi/uefidump/uefidump.c > + uefi/uefidump/uefidump.c \ > + uefi/uefirttime/uefirttime.c > > fwts_LDFLAGS = -ljson -lm > > diff --git a/src/lib/include/fwts_uefi.h b/src/lib/include/fwts_uefi.h > index f45027d..73cd773 100644 > --- a/src/lib/include/fwts_uefi.h > +++ b/src/lib/include/fwts_uefi.h > @@ -41,6 +41,13 @@ enum { > FWTS_UEFI_VAR_RUNTIME_ACCESS = 0x00000004 > }; > > +enum { > + FWTS_UEFI_TIME_ADJUST_DAYLIGHT = 0x01, > + FWTS_UEFI_TIME_IN_DAYLIGHT = 0x02 > +}; > + > +#define FWTS_UEFI_UNSPECIFIED_TIMEZONE 0x07FF > + > #if 0 > typedef struct { > char *description; > diff --git a/src/uefi/uefirttime/uefirttime.c b/src/uefi/uefirttime/uefirttime.c > new file mode 100644 > index 0000000..686cf2d > --- /dev/null > +++ b/src/uefi/uefirttime/uefirttime.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright (C) 2012 Canonical > + * > + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > + > +#include <inttypes.h> > +#include <stdio.h> > +#include <stddef.h> > +#include <sys/ioctl.h> > +#include <fcntl.h> > + > +#include "fwts.h" > +#include "fwts_uefi.h" > +#include "efi_runtime.h" > +#include "fwts_efi_module.h" > + > +#define IS_LEAP(year) \ > + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) > + > +static int fd; > +static uint32_t dayofmonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; > + > +static bool dayvalid(EFI_TIME *Time) > +{ > + if (Time->Day < 1) > + return false; > + > + if (Time->Day > dayofmonth[Time->Month - 1]) > + return false; > + > + /* check month 2 */ > + if (Time->Month == 2 && (!IS_LEAP(Time->Year) && Time->Day > 28)) > + return false; > + > + return true; > +} > + > +static bool checktimefields(fwts_framework *fw, EFI_TIME *Time) > +{ > + if (Time->Year < 1900 || Time->Year > 9999) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadYear", > + "Time returned an invalid year %" PRIu16 > + ", should be between 1900 and 9999.", > + Time->Year); > + return false; > + } > + > + if (Time->Month < 1 || Time->Month > 12) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadMonth", > + "Time returned an invalid month %" PRIu8 > + ", should be between 1 and 12.", > + Time->Month); > + return false; > + } > + > + if (!dayvalid(Time)) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadDay", > + "Time returned an invalid day %" PRIu8 > + ", should be between 1 and 28-31 depends on month/year.", > + Time->Day); > + return false; > + } > + > + if (Time->Hour > 23) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadHour", > + "Time returned an invalid hour %" PRIu8 > + ", should be between 0 and 23.", > + Time->Hour); > + return false; > + } > + > + if (Time->Minute > 59) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadMinute", > + "Time returned an invalid minute %" PRIu8 > + ", should be between 0 and 59.", > + Time->Minute); > + return false; > + } > + > + if (Time->Second > 59) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadSecond", > + "Time returned an invalid second %" PRIu8 > + ", should be between 0 and 59.", > + Time->Second); > + return false; > + } > + > + if (Time->Nanosecond > 999999999) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadNanosecond", > + "Time returned an invalid nanosecond %" PRIu32 > + ", should be between 0 and 999999999.", > + Time->Nanosecond); > + return false; > + } > + > + if (!(Time->TimeZone == FWTS_UEFI_UNSPECIFIED_TIMEZONE || > + (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadTimezone", > + "Time returned an invalid timezone %" PRId16 > + ", should be between -1440 and 1440 or 2047.", > + Time->TimeZone); > + return false; > + } > + > + if (Time->Daylight & (~(FWTS_UEFI_TIME_ADJUST_DAYLIGHT | > + FWTS_UEFI_TIME_IN_DAYLIGHT))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "UEFIRuntimeTimeFieldBadDaylight", > + "Time returned an invalid daylight %" PRIu8 > + ", all other bits except UEFI_TIME_IN_DAYLIGHT and " > + "UEFI_TIME_ADJUST_DAYLIGHT must be zero.", > + Time->Daylight); > + return false; > + } > + return true; > +} > + > +static int uefirttime_init(fwts_framework *fw) > +{ > + if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) { > + fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted."); > + return FWTS_ABORTED; > + } > + > + if (fwts_lib_efi_runtime_load_module(fw) != FWTS_OK) { > + fwts_log_info(fw, "Cannot load efi_runtime module. Aborted."); > + return FWTS_ABORTED; > + } > + > + fd = open("/dev/efi_runtime", O_RDONLY); > + if (fd == -1) { > + fwts_log_info(fw, "Cannot open efi_runtime driver. Aborted."); > + return FWTS_ABORTED; > + } > + > + return FWTS_OK; > +} > + > +static int uefirttime_deinit(fwts_framework *fw) > +{ > + > + close(fd); > + > + return FWTS_OK; > +} > + > + > +static int uefirttime_test1(fwts_framework *fw) > +{ > + long ioret; > + struct efi_gettime gettime; > + EFI_TIME efi_time; > + > + EFI_TIME_CAPABILITIES efi_time_cap; > + uint64_t status; > + > + gettime.Capabilities = &efi_time_cap; > + gettime.Time = &efi_time; > + gettime.status = &status; > + > + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); > + > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", > + "Failed to get time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!checktimefields(fw, gettime.Time)) > + return FWTS_ERROR; > + > + fwts_passed(fw, "UEFI runtime service GetTime interface test passed."); > + > + return FWTS_OK; > +} > + > +static int uefirttime_test2(fwts_framework *fw) > +{ > + > + long ioret; > + struct efi_settime settime; > + uint64_t status; > + struct efi_gettime gettime; > + > + EFI_TIME oldtime; > + EFI_TIME newtime; > + EFI_TIME time; > + EFI_TIME_CAPABILITIES efi_time_cap; > + > + gettime.Capabilities = &efi_time_cap; > + gettime.Time = &oldtime; > + gettime.status = &status; > + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); > + > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", > + "Failed to get time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + /* refer to UEFI SCT 2.3 test items */ > + /* change year */ > + time = oldtime; > + if (time.Year != 2012) > + time.Year = 2012; > + else > + time.Year = 2016; > + > + /* change month */ > + if (time.Month != 1) > + time.Month = 1; > + else > + time.Month = 12; > + > + /* Change daylight */ > + if (time.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT) > + time.Daylight &= ~FWTS_UEFI_TIME_ADJUST_DAYLIGHT; > + else > + time.Daylight |= FWTS_UEFI_TIME_ADJUST_DAYLIGHT; > + > + /* Change time zone */ > + if (time.TimeZone != 0) > + time.TimeZone = 0; > + else > + time.TimeZone = 1; > + > + settime.Time = &time; > + settime.status = &status; > + > + ioret = ioctl(fd, EFI_RUNTIME_SET_TIME, &settime); > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", > + "Failed to set time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + sleep(1); > + > + gettime.Time = &newtime; > + > + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); > + > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", > + "Failed to get time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!((oldtime.Year == 2012) && (newtime.Year == 2016)) && > + !((oldtime.Year != 2012) && (newtime.Year == 2012))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeYear", > + "Failed to set year with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!((oldtime.Month == 1) && (newtime.Month == 12)) && > + !((oldtime.Month != 1) && (newtime.Month == 1))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeMonth", > + "Failed to set month with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!((oldtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT) && > + (!(newtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT))) && > + !((!(oldtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT)) && > + (newtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeDaylight", > + "Failed to set daylight with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + if (!((oldtime.TimeZone == 0) && (newtime.TimeZone == 1)) && > + !((oldtime.TimeZone != 0) && (newtime.TimeZone == 0))) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeTimezone", > + "Failed to set timezone with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + /* restore the previous time. */ > + settime.Time = &oldtime; > + ioret = ioctl(fd, EFI_RUNTIME_SET_TIME, &settime); > + if (ioret == -1) { > + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", > + "Failed to set time with UEFI runtime service."); > + return FWTS_ERROR; > + } > + > + fwts_passed(fw, "UEFI runtime service SetTime interface test passed."); > + > + return FWTS_OK; > +} > + > +static fwts_framework_minor_test uefirttime_tests[] = { > + { uefirttime_test1, "Test UEFI RT service get time interface." }, > + { uefirttime_test2, "Test UEFI RT service set time interface." }, > + { NULL, NULL } > +}; > + > +static fwts_framework_ops uefirttime_ops = { > + .description = "UEFI Runtime service time interface tests.", > + .init = uefirttime_init, > + .deinit = uefirttime_deinit, > + .minor_tests = uefirttime_tests > +}; > + > +FWTS_REGISTER(uefirttime, &uefirttime_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UNSAFE | FWTS_FLAG_ROOT_PRIV); > Acked-by: Alex Hung <alex.hung@canonical.com>
diff --git a/src/Makefile.am b/src/Makefile.am index 6054eb3..b7adc20 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ # but libfwts.so depends on libraries produced by acpica/source/compiler. SUBDIRS = acpica/source/compiler lib acpica -AM_CPPFLAGS = -I$(top_srcdir)/src/lib/include -I$(top_srcdir)/src/acpica/source/include -Wall -Werror +AM_CPPFLAGS = -I$(top_srcdir)/src/lib/include -I$(top_srcdir)/src/acpica/source/include -I$(top_srcdir)/efi_runtime -Wall -Werror bin_PROGRAMS = fwts fwts_SOURCES = main.c \ @@ -66,7 +66,8 @@ fwts_SOURCES = main.c \ kernel/version/version.c \ kernel/oops/oops.c \ uefi/csm/csm.c \ - uefi/uefidump/uefidump.c + uefi/uefidump/uefidump.c \ + uefi/uefirttime/uefirttime.c fwts_LDFLAGS = -ljson -lm diff --git a/src/lib/include/fwts_uefi.h b/src/lib/include/fwts_uefi.h index f45027d..73cd773 100644 --- a/src/lib/include/fwts_uefi.h +++ b/src/lib/include/fwts_uefi.h @@ -41,6 +41,13 @@ enum { FWTS_UEFI_VAR_RUNTIME_ACCESS = 0x00000004 }; +enum { + FWTS_UEFI_TIME_ADJUST_DAYLIGHT = 0x01, + FWTS_UEFI_TIME_IN_DAYLIGHT = 0x02 +}; + +#define FWTS_UEFI_UNSPECIFIED_TIMEZONE 0x07FF + #if 0 typedef struct { char *description; diff --git a/src/uefi/uefirttime/uefirttime.c b/src/uefi/uefirttime/uefirttime.c new file mode 100644 index 0000000..686cf2d --- /dev/null +++ b/src/uefi/uefirttime/uefirttime.c @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2012 Canonical + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <inttypes.h> +#include <stdio.h> +#include <stddef.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#include "fwts.h" +#include "fwts_uefi.h" +#include "efi_runtime.h" +#include "fwts_efi_module.h" + +#define IS_LEAP(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +static int fd; +static uint32_t dayofmonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +static bool dayvalid(EFI_TIME *Time) +{ + if (Time->Day < 1) + return false; + + if (Time->Day > dayofmonth[Time->Month - 1]) + return false; + + /* check month 2 */ + if (Time->Month == 2 && (!IS_LEAP(Time->Year) && Time->Day > 28)) + return false; + + return true; +} + +static bool checktimefields(fwts_framework *fw, EFI_TIME *Time) +{ + if (Time->Year < 1900 || Time->Year > 9999) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadYear", + "Time returned an invalid year %" PRIu16 + ", should be between 1900 and 9999.", + Time->Year); + return false; + } + + if (Time->Month < 1 || Time->Month > 12) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadMonth", + "Time returned an invalid month %" PRIu8 + ", should be between 1 and 12.", + Time->Month); + return false; + } + + if (!dayvalid(Time)) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadDay", + "Time returned an invalid day %" PRIu8 + ", should be between 1 and 28-31 depends on month/year.", + Time->Day); + return false; + } + + if (Time->Hour > 23) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadHour", + "Time returned an invalid hour %" PRIu8 + ", should be between 0 and 23.", + Time->Hour); + return false; + } + + if (Time->Minute > 59) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadMinute", + "Time returned an invalid minute %" PRIu8 + ", should be between 0 and 59.", + Time->Minute); + return false; + } + + if (Time->Second > 59) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadSecond", + "Time returned an invalid second %" PRIu8 + ", should be between 0 and 59.", + Time->Second); + return false; + } + + if (Time->Nanosecond > 999999999) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadNanosecond", + "Time returned an invalid nanosecond %" PRIu32 + ", should be between 0 and 999999999.", + Time->Nanosecond); + return false; + } + + if (!(Time->TimeZone == FWTS_UEFI_UNSPECIFIED_TIMEZONE || + (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadTimezone", + "Time returned an invalid timezone %" PRId16 + ", should be between -1440 and 1440 or 2047.", + Time->TimeZone); + return false; + } + + if (Time->Daylight & (~(FWTS_UEFI_TIME_ADJUST_DAYLIGHT | + FWTS_UEFI_TIME_IN_DAYLIGHT))) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "UEFIRuntimeTimeFieldBadDaylight", + "Time returned an invalid daylight %" PRIu8 + ", all other bits except UEFI_TIME_IN_DAYLIGHT and " + "UEFI_TIME_ADJUST_DAYLIGHT must be zero.", + Time->Daylight); + return false; + } + return true; +} + +static int uefirttime_init(fwts_framework *fw) +{ + if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) { + fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted."); + return FWTS_ABORTED; + } + + if (fwts_lib_efi_runtime_load_module(fw) != FWTS_OK) { + fwts_log_info(fw, "Cannot load efi_runtime module. Aborted."); + return FWTS_ABORTED; + } + + fd = open("/dev/efi_runtime", O_RDONLY); + if (fd == -1) { + fwts_log_info(fw, "Cannot open efi_runtime driver. Aborted."); + return FWTS_ABORTED; + } + + return FWTS_OK; +} + +static int uefirttime_deinit(fwts_framework *fw) +{ + + close(fd); + + return FWTS_OK; +} + + +static int uefirttime_test1(fwts_framework *fw) +{ + long ioret; + struct efi_gettime gettime; + EFI_TIME efi_time; + + EFI_TIME_CAPABILITIES efi_time_cap; + uint64_t status; + + gettime.Capabilities = &efi_time_cap; + gettime.Time = &efi_time; + gettime.status = &status; + + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); + + if (ioret == -1) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", + "Failed to get time with UEFI runtime service."); + return FWTS_ERROR; + } + + if (!checktimefields(fw, gettime.Time)) + return FWTS_ERROR; + + fwts_passed(fw, "UEFI runtime service GetTime interface test passed."); + + return FWTS_OK; +} + +static int uefirttime_test2(fwts_framework *fw) +{ + + long ioret; + struct efi_settime settime; + uint64_t status; + struct efi_gettime gettime; + + EFI_TIME oldtime; + EFI_TIME newtime; + EFI_TIME time; + EFI_TIME_CAPABILITIES efi_time_cap; + + gettime.Capabilities = &efi_time_cap; + gettime.Time = &oldtime; + gettime.status = &status; + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); + + if (ioret == -1) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", + "Failed to get time with UEFI runtime service."); + return FWTS_ERROR; + } + + /* refer to UEFI SCT 2.3 test items */ + /* change year */ + time = oldtime; + if (time.Year != 2012) + time.Year = 2012; + else + time.Year = 2016; + + /* change month */ + if (time.Month != 1) + time.Month = 1; + else + time.Month = 12; + + /* Change daylight */ + if (time.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT) + time.Daylight &= ~FWTS_UEFI_TIME_ADJUST_DAYLIGHT; + else + time.Daylight |= FWTS_UEFI_TIME_ADJUST_DAYLIGHT; + + /* Change time zone */ + if (time.TimeZone != 0) + time.TimeZone = 0; + else + time.TimeZone = 1; + + settime.Time = &time; + settime.status = &status; + + ioret = ioctl(fd, EFI_RUNTIME_SET_TIME, &settime); + if (ioret == -1) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", + "Failed to set time with UEFI runtime service."); + return FWTS_ERROR; + } + + sleep(1); + + gettime.Time = &newtime; + + ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); + + if (ioret == -1) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", + "Failed to get time with UEFI runtime service."); + return FWTS_ERROR; + } + + if (!((oldtime.Year == 2012) && (newtime.Year == 2016)) && + !((oldtime.Year != 2012) && (newtime.Year == 2012))) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeYear", + "Failed to set year with UEFI runtime service."); + return FWTS_ERROR; + } + + if (!((oldtime.Month == 1) && (newtime.Month == 12)) && + !((oldtime.Month != 1) && (newtime.Month == 1))) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeMonth", + "Failed to set month with UEFI runtime service."); + return FWTS_ERROR; + } + + if (!((oldtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT) && + (!(newtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT))) && + !((!(oldtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT)) && + (newtime.Daylight & FWTS_UEFI_TIME_ADJUST_DAYLIGHT))) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeDaylight", + "Failed to set daylight with UEFI runtime service."); + return FWTS_ERROR; + } + + if (!((oldtime.TimeZone == 0) && (newtime.TimeZone == 1)) && + !((oldtime.TimeZone != 0) && (newtime.TimeZone == 0))) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTimeTimezone", + "Failed to set timezone with UEFI runtime service."); + return FWTS_ERROR; + } + + /* restore the previous time. */ + settime.Time = &oldtime; + ioret = ioctl(fd, EFI_RUNTIME_SET_TIME, &settime); + if (ioret == -1) { + fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", + "Failed to set time with UEFI runtime service."); + return FWTS_ERROR; + } + + fwts_passed(fw, "UEFI runtime service SetTime interface test passed."); + + return FWTS_OK; +} + +static fwts_framework_minor_test uefirttime_tests[] = { + { uefirttime_test1, "Test UEFI RT service get time interface." }, + { uefirttime_test2, "Test UEFI RT service set time interface." }, + { NULL, NULL } +}; + +static fwts_framework_ops uefirttime_ops = { + .description = "UEFI Runtime service time interface tests.", + .init = uefirttime_init, + .deinit = uefirttime_deinit, + .minor_tests = uefirttime_tests +}; + +FWTS_REGISTER(uefirttime, &uefirttime_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UNSAFE | FWTS_FLAG_ROOT_PRIV);
Add the set and get time tests of the UEFI runtime service interfaces which test via efi_runtime driver. Signed-off-by: Ivan Hu <ivan.hu@canonical.com> --- src/Makefile.am | 5 +- src/lib/include/fwts_uefi.h | 7 + src/uefi/uefirttime/uefirttime.c | 328 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 src/uefi/uefirttime/uefirttime.c