From patchwork Thu Oct 18 15:52:28 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [2/2, RESEND] uefirttime: add fwts tests for the UEFI get/set time runtime services Date: Thu, 18 Oct 2012 05:52:28 -0000 From: IvanHu X-Patchwork-Id: 192369 Message-Id: <1350575548-28548-1-git-send-email-ivan.hu@canonical.com> To: fwts-devel@lists.ubuntu.com Add the set and get time tests of the UEFI runtime service interfaces which test via efi_runtime driver. Signed-off-by: Ivan Hu Acked-by: Colin Ian King Acked-by: Alex Hung --- 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 +#include +#include +#include +#include + +#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);