ACK: [PATCH 2/2][RESEND] uefirttime: add fwts tests for the UEFI get/set time runtime services
Colin Ian King
colin.king at canonical.com
Thu Oct 18 16:20:56 UTC 2012
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 at 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 at canonical.com>
More information about the fwts-devel
mailing list