diff --git a/commands/crontab.c b/commands/crontab.c new file mode 100644 index 0000000..b646842 --- /dev/null +++ b/commands/crontab.c @@ -0,0 +1,127 @@ +/* crontab.c - command to test current date/time. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +static grub_err_t +grub_cmd_crontab (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_datetime datetime; + int dow, i; + int limit[5][2] = {{0, 59}, {0, 23}, {1, 31}, {1, 12}, {0, 7}}; + int field[5]; + + if (grub_get_datetime (&datetime)) + return grub_errno; + + dow = grub_get_day_of_week (&datetime); + + field[0] = datetime.minute; + field[1] = datetime.hour; + field[2] = datetime.day; + field[3] = datetime.month; + field[4] = dow; + + for (i = 0; i < 5; i++) + { + char *p; + int ok = 0; + + if (i >= argc) + return 0; + + p = args[i]; + while (1) + { + int m1, m2, m3, j; + + if (*p == '*') + { + m1 = limit[i][0]; + m2 = limit[i][1]; + p++; + } + else + { + m1 = grub_strtoul (p, &p, 0); + + if (*p == '-') + { + p++; + m2 = grub_strtoul (p, &p, 0); + } + else + m2 = m1; + } + + if ((m1 < limit[i][0]) || (m2 > limit[i][1]) || (m1 > m2)) + break; + + if (*p == '/') + { + p++; + m3 = grub_strtoul (p, &p, 0); + } + else + m3 = 1; + + for (j = m1; j <= m2; j+= m3) + { + if (j == field[i]) + { + ok = 1; + break; + } + } + + if (ok) + break; + + if (*p == ',') + p++; + else + break; + } + + if (! ok) + break; + } + + return (i == 5) ? 0 : grub_error (GRUB_ERR_TEST_FAILURE, "false"); +} + +GRUB_MOD_INIT(crontab) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("crontab", grub_cmd_crontab, + GRUB_COMMAND_FLAG_BOTH, + "crontab min hour day_of_month month day_of_week", + "Command to test current date/time.", 0); +} + +GRUB_MOD_FINI(crontab) +{ + grub_unregister_command ("crontab"); +} diff --git a/commands/date.c b/commands/date.c new file mode 100644 index 0000000..ec50c45 --- /dev/null +++ b/commands/date.c @@ -0,0 +1,161 @@ +/* date.c - command to set/get current date/time. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +static int +get_bcd (char **str) +{ + int res, i; + + res = 0; + for (i = 0; i < 2; i++) + { + if ((**str >= '0') && (**str <= '9')) + res = res * 10 + (**str - '0'); + else + return -1; + + (*str)++; + } + + return res; +} + +static grub_err_t +grub_cmd_date (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_datetime datetime; + char* dow_names[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + int pos, mask; + char *p; + + if (argc == 0) + { + if (grub_get_datetime (&datetime)) + return grub_errno; + + grub_printf ("%d-%02d-%02d %02d:%02d:%02d %s\n", + datetime.year, datetime.month, datetime.day, + datetime.hour, datetime.minute, datetime.second, + dow_names[grub_get_day_of_week (&datetime)]); + + return 0; + } + + p = args[0]; + mask = 0; + + for (pos = 0; (*p); pos++) + { + int n; + + n = get_bcd (&p); + if (n < 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid date"); + + switch (pos) + { + case 0: + if ((n < 1) || (n > 12)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid date"); + + mask |= GRUB_DATETIME_SET_MONTH; + datetime.month = n; + break; + + case 1: + if ((n < 1) || (n > 31)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid date"); + + mask |= GRUB_DATETIME_SET_DAY; + datetime.day = n; + break; + + case 2: + if (n > 23) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid date"); + + mask |= GRUB_DATETIME_SET_HOUR; + datetime.hour = n; + break; + + case 3: + if (n > 59) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid date"); + + mask |= GRUB_DATETIME_SET_MINUTE; + datetime.minute = n; + break; + + case 4: + if (n > 99) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid date"); + + mask |= GRUB_DATETIME_SET_YEAR; + datetime.year = n; + if ((*p >= '0') && (*p <= '9')) + { + n = get_bcd (&p); + if ((n < 0) || (n > 99)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid date"); + + datetime.year = datetime.year * 100 + n; + } + else + datetime.year += (datetime.year >= 80) ? 1900 : 2000; + + if (*p == '.') + p++; + else if (*p != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid date"); + + break; + + case 5: + mask |= GRUB_DATETIME_SET_SECOND; + datetime.second = n; + } + + if ((*p == '-') || (*p == ':')) + p++; + } + + return grub_set_datetime (&datetime, mask); +} + +GRUB_MOD_INIT(checktime) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("date", grub_cmd_date, + GRUB_COMMAND_FLAG_BOTH, + "date [MMDDhhmm[[CC]YY][.ss]]", + "Command to get/set current date/time.", 0); +} + +GRUB_MOD_FINI(checktime) +{ + grub_unregister_command ("date"); +} diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 4827c0f..f2d5875 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -101,7 +101,7 @@ pkglib_MODULES = _linux.mod linux.mod normal.mod \ _multiboot.mod multiboot.mod aout.mod \ play.mod cpuid.mod serial.mod ata.mod \ memdisk.mod pci.mod lspci.mod reboot.mod \ - halt.mod + halt.mod datetime.mod date.mod crontab.mod # For _linux.mod. _linux_mod_SOURCES = loader/i386/pc/linux.c @@ -186,4 +186,19 @@ lspci_mod_SOURCES = commands/lspci.c lspci_mod_CFLAGS = $(COMMON_CFLAGS) lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For datetime.mod +datetime_mod_SOURCES = kern/i386/datetime.c kern/generic/get_dow.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For date.mod +date_mod_SOURCES = commands/date.c +date_mod_CFLAGS = $(COMMON_CFLAGS) +date_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For crontab.mod +crontab_mod_SOURCES = commands/crontab.c +crontab_mod_CFLAGS = $(COMMON_CFLAGS) +crontab_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 2ce21b1..a7a2483 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -75,7 +75,8 @@ grub_install_SOURCES = util/i386/efi/grub-install.in # Modules. pkglib_MODULES = kernel.mod normal.mod _chain.mod chain.mod appleldr.mod \ - _linux.mod linux.mod cpuid.mod halt.mod reboot.mod pci.mod lspci.mod + _linux.mod linux.mod cpuid.mod halt.mod reboot.mod pci.mod lspci.mod \ + datetime.mod date.mod crontab.mod # For kernel.mod. kernel_mod_EXPORTS = no @@ -167,4 +168,19 @@ lspci_mod_SOURCES = commands/lspci.c lspci_mod_CFLAGS = $(COMMON_CFLAGS) lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For datetime.mod +datetime_mod_SOURCES = kern/efi/datetime.c kern/generic/get_dow.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For date.mod +date_mod_SOURCES = commands/date.c +date_mod_CFLAGS = $(COMMON_CFLAGS) +date_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For crontab.mod +crontab_mod_SOURCES = commands/crontab.c +crontab_mod_CFLAGS = $(COMMON_CFLAGS) +crontab_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index a93845e..e6dc4bc 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -104,7 +104,8 @@ grub_install_SOURCES = util/ieee1275/grub-install.in # Modules. pkglib_MODULES = normal.mod halt.mod reboot.mod suspend.mod cpuid.mod \ multiboot.mod _multiboot.mod aout.mod serial.mod linux.mod \ - _linux.mod nand.mod memdisk.mod pci.mod lspci.mod + _linux.mod nand.mod memdisk.mod pci.mod lspci.mod datetime.mod \ + date.mod crontab.mod # For normal.mod. normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ @@ -188,4 +189,19 @@ lspci_mod_SOURCES = commands/lspci.c lspci_mod_CFLAGS = $(COMMON_CFLAGS) lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For datetime.mod +datetime_mod_SOURCES = kern/i386/datetime.c kern/generic/get_dow.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For date.mod +date_mod_SOURCES = commands/date.c +date_mod_CFLAGS = $(COMMON_CFLAGS) +date_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For crontab.mod +crontab_mod_SOURCES = commands/crontab.c +crontab_mod_CFLAGS = $(COMMON_CFLAGS) +crontab_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index c1e4ac4..aa19219 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -163,7 +163,8 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \ ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \ - aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod + aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \ + crontab.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -340,4 +341,19 @@ pxecmd_mod_SOURCES = commands/i386/pc/pxecmd.c pxecmd_mod_CFLAGS = $(COMMON_CFLAGS) pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For datetime.mod +datetime_mod_SOURCES = kern/i386/datetime.c kern/generic/get_dow.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For date.mod +date_mod_SOURCES = commands/date.c +date_mod_CFLAGS = $(COMMON_CFLAGS) +date_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For crontab.mod +crontab_mod_SOURCES = commands/crontab.c +crontab_mod_CFLAGS = $(COMMON_CFLAGS) +crontab_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 25dc8eb..d911b31 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -77,7 +77,8 @@ grub_install_SOURCES = util/i386/efi/grub-install.in # Modules. pkglib_MODULES = kernel.mod normal.mod _chain.mod chain.mod appleldr.mod \ - cpuid.mod halt.mod reboot.mod _linux.mod linux.mod pci.mod lspci.mod + cpuid.mod halt.mod reboot.mod _linux.mod linux.mod pci.mod lspci.mod \ + datetime.mod date.mod crontab.mod # For kernel.mod. kernel_mod_EXPORTS = no @@ -167,4 +168,19 @@ lspci_mod_SOURCES = commands/lspci.c lspci_mod_CFLAGS = $(COMMON_CFLAGS) lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For datetime.mod +datetime_mod_SOURCES = kern/efi/datetime.c kern/generic/get_dow.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For date.mod +date_mod_SOURCES = commands/date.c +date_mod_CFLAGS = $(COMMON_CFLAGS) +date_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For crontab.mod +crontab_mod_SOURCES = commands/crontab.c +crontab_mod_CFLAGS = $(COMMON_CFLAGS) +crontab_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff --git a/include/grub/datetime.h b/include/grub/datetime.h new file mode 100644 index 0000000..b8c9f7e --- /dev/null +++ b/include/grub/datetime.h @@ -0,0 +1,57 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef KERNEL_DATETIME_HEADER +#define KERNEL_DATETIME_HEADER 1 + +#include +#include + +#define GRUB_DATETIME_SET_YEAR 1 +#define GRUB_DATETIME_SET_MONTH 2 +#define GRUB_DATETIME_SET_DAY 4 +#define GRUB_DATETIME_SET_DATE (GRUB_DATETIME_SET_YEAR | \ + GRUB_DATETIME_SET_MONTH | \ + GRUB_DATETIME_SET_DAY) + +#define GRUB_DATETIME_SET_HOUR 8 +#define GRUB_DATETIME_SET_MINUTE 16 +#define GRUB_DATETIME_SET_SECOND 32 +#define GRUB_DATETIME_SET_TIME (GRUB_DATETIME_SET_HOUR | \ + GRUB_DATETIME_SET_MINUTE | \ + GRUB_DATETIME_SET_SECOND) + +struct grub_datetime +{ + grub_uint16_t year; + grub_uint8_t month; + grub_uint8_t day; + grub_uint8_t hour; + grub_uint8_t minute; + grub_uint8_t second; +}; + +/* Return date and time. */ +grub_err_t grub_get_datetime (struct grub_datetime *datetime); + +/* Set date and time. */ +grub_err_t grub_set_datetime (struct grub_datetime *datetime, int mask); + +int grub_get_day_of_week (struct grub_datetime *datetime); + +#endif /* ! KERNEL_DATETIME_HEADER */ diff --git a/include/grub/i386/cmos.h b/include/grub/i386/cmos.h new file mode 100644 index 0000000..d482a7d --- /dev/null +++ b/include/grub/i386/cmos.h @@ -0,0 +1,74 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_CPU_CMOS_H +#define GRUB_CPU_CMOS_H 1 + +#include +#include + +#define GRUB_CMOS_ADDR_REG 0x70 +#define GRUB_CMOS_DATA_REG 0x71 + +#define GRUB_CMOS_INDEX_SECOND 0 +#define GRUB_CMOS_INDEX_SECOND_ALARM 1 +#define GRUB_CMOS_INDEX_MINUTE 2 +#define GRUB_CMOS_INDEX_MINUTE_ALARM 3 +#define GRUB_CMOS_INDEX_HOUR 4 +#define GRUB_CMOS_INDEX_HOUR_ALARM 5 +#define GRUB_CMOS_INDEX_DAY_OF_WEEK 6 +#define GRUB_CMOS_INDEX_DAY_OF_MONTH 7 +#define GRUB_CMOS_INDEX_MONTH 8 +#define GRUB_CMOS_INDEX_YEAR 9 + +#define GRUB_CMOS_INDEX_STATUS_A 0xA +#define GRUB_CMOS_INDEX_STATUS_B 0xB +#define GRUB_CMOS_INDEX_STATUS_C 0xC +#define GRUB_CMOS_INDEX_STATUS_D 0xD + +#define GRUB_CMOS_STATUS_B_DAYLIGHT 1 +#define GRUB_CMOS_STATUS_B_24HOUR 2 +#define GRUB_CMOS_STATUS_B_BINARY 4 + +static inline grub_uint8_t +grub_bcd_to_num (grub_uint8_t a) +{ + return ((a >> 4) * 10 + (a & 0xF)); +} + +static inline grub_uint8_t +grub_num_to_bcd (grub_uint8_t a) +{ + return (((a / 10) << 4) + (a % 10)); +} + +static inline grub_uint8_t +grub_cmos_read (grub_uint8_t index) +{ + grub_outb (index, GRUB_CMOS_ADDR_REG); + return grub_inb (GRUB_CMOS_DATA_REG); +} + +static inline void +grub_cmos_write (grub_uint8_t index, grub_uint8_t value) +{ + grub_outb (index, GRUB_CMOS_ADDR_REG); + grub_outb (value, GRUB_CMOS_DATA_REG); +} + +#endif /* GRUB_CPU_PCI_H */ diff --git a/kern/efi/datetime.c b/kern/efi/datetime.c new file mode 100644 index 0000000..4ba38be --- /dev/null +++ b/kern/efi/datetime.c @@ -0,0 +1,87 @@ +/* kern/efi/datetime.c - efi datetime function. + * + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +grub_err_t +grub_get_datetime (struct grub_datetime *datetime) +{ + grub_efi_status_t status; + struct grub_efi_time efi_time; + + status = efi_call_2 (grub_efi_system_table->runtime_services->get_time, + &efi_time, 0); + + if (status) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "can\'t get datetime"); + else + { + datetime->year = efi_time.year; + datetime->month = efi_time.month; + datetime->day = efi_time.day; + datetime->hour = efi_time.hour; + datetime->minute = efi_time.minute; + datetime->second = efi_time.second; + } + + return 0; +} + +grub_err_t +grub_set_datetime (struct grub_datetime *datetime, int mask) +{ + grub_efi_status_t status; + struct grub_efi_time efi_time; + + status = efi_call_2 (grub_efi_system_table->runtime_services->get_time, + &efi_time, 0); + + if (status) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "can\'t get datetime"); + + if (mask & GRUB_DATETIME_SET_YEAR) + efi_time.year = datetime->year; + + if (mask & GRUB_DATETIME_SET_MONTH) + efi_time.month = datetime->month; + + if (mask & GRUB_DATETIME_SET_DAY) + efi_time.day = datetime->day; + + if (mask & GRUB_DATETIME_SET_HOUR) + efi_time.hour = datetime->hour; + + if (mask & GRUB_DATETIME_SET_MINUTE) + efi_time.minute = datetime->minute; + + if (mask & GRUB_DATETIME_SET_SECOND) + efi_time.second = datetime->second; + + status = efi_call_1 (grub_efi_system_table->runtime_services->set_time, + &efi_time); + + if (status) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "can\'t set datetime"); + + return 0; +} diff --git a/kern/generic/get_dow.c b/kern/generic/get_dow.c new file mode 100755 index 0000000..fd1a032 --- /dev/null +++ b/kern/generic/get_dow.c @@ -0,0 +1,32 @@ +/* get_dow - Calculate the day of week. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include + +int +grub_get_day_of_week (struct grub_datetime *datetime) +{ + int a, y, m; + + a = (14 - datetime->month) / 12; + y = datetime->year - a; + m = datetime->month + 12 * a - 2; + + return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7; +} diff --git a/kern/i386/datetime.c b/kern/i386/datetime.c new file mode 100644 index 0000000..466a404 --- /dev/null +++ b/kern/i386/datetime.c @@ -0,0 +1,175 @@ +/* kern/i386/datetime.c - x86 CMOS datetime function. + * + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include + +grub_err_t +grub_get_datetime (struct grub_datetime *datetime) +{ + int is_bcd, is_12hour; + grub_uint8_t value, flag; + + flag = grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B); + + is_bcd = ! (flag & GRUB_CMOS_STATUS_B_BINARY); + + value = grub_cmos_read (GRUB_CMOS_INDEX_YEAR); + if (is_bcd) + value = grub_bcd_to_num (value); + + datetime->year = value; + datetime->year += (value < 80) ? 2000 : 1900; + + value = grub_cmos_read (GRUB_CMOS_INDEX_MONTH); + if (is_bcd) + value = grub_bcd_to_num (value); + + datetime->month = value; + + value = grub_cmos_read (GRUB_CMOS_INDEX_DAY_OF_MONTH); + if (is_bcd) + value = grub_bcd_to_num (value); + + datetime->day = value; + + is_12hour = ! (flag & GRUB_CMOS_STATUS_B_24HOUR); + + value = grub_cmos_read (GRUB_CMOS_INDEX_HOUR); + if (is_12hour) + { + is_12hour = (value & 0x80); + + value &= 0x7F; + value--; + } + + if (is_bcd) + value = grub_bcd_to_num (value); + + if (is_12hour) + value += 12; + + datetime->hour = value; + + value = grub_cmos_read (GRUB_CMOS_INDEX_MINUTE); + if (is_bcd) + value = grub_bcd_to_num (value); + + datetime->minute = value; + + value = grub_cmos_read (GRUB_CMOS_INDEX_SECOND); + if (is_bcd) + value = grub_bcd_to_num (value); + + datetime->second = value; + + return 0; +} + +grub_err_t +grub_set_datetime (struct grub_datetime *datetime, int mask) +{ + int is_bcd; + grub_uint8_t value, flag; + + flag = grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B); + + is_bcd = ! (flag & GRUB_CMOS_STATUS_B_BINARY); + + if (mask & GRUB_DATETIME_SET_YEAR) + { + value = ((datetime->year >= 2000) ? datetime->year - 2000 : + datetime->year - 1900); + + if (is_bcd) + value = grub_num_to_bcd (value); + + grub_cmos_write (GRUB_CMOS_INDEX_YEAR, value); + } + + if (mask & GRUB_DATETIME_SET_MONTH) + { + value = datetime->month; + + if (is_bcd) + value = grub_num_to_bcd (value); + + grub_cmos_write (GRUB_CMOS_INDEX_MONTH, value); + } + + if (mask & GRUB_DATETIME_SET_DAY) + { + value = datetime->day; + + if (is_bcd) + value = grub_num_to_bcd (value); + + grub_cmos_write (GRUB_CMOS_INDEX_DAY_OF_MONTH, value); + } + + if (mask & GRUB_DATETIME_SET_HOUR) + { + int is_12hour; + + value = datetime->hour; + + is_12hour = (! (flag & GRUB_CMOS_STATUS_B_24HOUR)); + + if (is_12hour) + { + value++; + + if (value > 12) + value -= 12; + else + is_12hour = 0; + } + + if (is_bcd) + value = grub_num_to_bcd (value); + + if (is_12hour) + value |= 0x80; + + grub_cmos_write (GRUB_CMOS_INDEX_HOUR, value); + } + + if (mask & GRUB_DATETIME_SET_MINUTE) + { + value = datetime->minute; + + if (is_bcd) + value = grub_num_to_bcd (value); + + grub_cmos_write (GRUB_CMOS_INDEX_MINUTE, value); + } + + if (mask & GRUB_DATETIME_SET_SECOND) + { + value = datetime->second; + + if (is_bcd) + value = grub_num_to_bcd (value); + + grub_cmos_write (GRUB_CMOS_INDEX_SECOND, value); + } + + return 0; +}