clock.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * clock.c
  3. *
  4. * Copyright (C) 2013 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <clock.h>
  20. #include <exception.h>
  21. #include <syscalls.h>
  22. #include <irq.h>
  23. #include <user.h>
  24. static clock_time_t clock_current_time;
  25. static byte_t clock_settings;
  26. void clock_irq(registers_t *regs, byte_t irq_num)
  27. {
  28. bool_t pm = FALSE;
  29. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_SECONDS_REG);
  30. byte_t seconds = cpu_read_port_byte(CMOS_DATA_PORT);
  31. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_MINUTES_REG);
  32. byte_t minutes = cpu_read_port_byte(CMOS_DATA_PORT);
  33. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_HOURS_REG);
  34. byte_t hours = cpu_read_port_byte(CMOS_DATA_PORT);
  35. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_DAY_REG);
  36. byte_t day = cpu_read_port_byte(CMOS_DATA_PORT);
  37. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_MONTH_REG);
  38. byte_t month = cpu_read_port_byte(CMOS_DATA_PORT);
  39. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_YEAR_REG);
  40. byte_t year = cpu_read_port_byte(CMOS_DATA_PORT);
  41. if (hours & CLOCK_PM_BIT) pm = TRUE;
  42. hours &= ~CLOCK_PM_BIT;
  43. if (!(clock_settings & CLOCK_BINARY_MODE))
  44. {
  45. hours = (hours >> 4) * 10 + (hours & 0x0F);
  46. minutes = (minutes >> 4) * 10 + (minutes & 0x0F);
  47. seconds = (seconds >> 4) * 10 + (seconds & 0x0F);
  48. day = (day >> 4) * 10 + (day & 0x0F);
  49. month = (month >> 4) * 10 + (month & 0x0F);
  50. year = (year >> 4) * 10 + (year & 0x0F);
  51. }
  52. if (!(clock_settings & CLOCK_24HOUR_MODE))
  53. {
  54. if (pm) hours += 12;
  55. else if (hours == 12) hours = 0;
  56. }
  57. clock_current_time.seconds = seconds;
  58. clock_current_time.minutes = minutes;
  59. clock_current_time.hours = hours;
  60. clock_current_time.day = day;
  61. clock_current_time.month = month;
  62. clock_current_time.year = year;
  63. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_STC_REG);
  64. cpu_read_port_byte(CMOS_DATA_PORT);
  65. }
  66. bool_t clock_check_time(clock_time_t *time)
  67. {
  68. byte_t max_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  69. if (time->year % 4 == 0 && (time->year % 100 != 0 || time->year % 400 == 0)) max_days[1]++;
  70. if (time->seconds >= 60) return FALSE;
  71. if (time->minutes >= 60) return FALSE;
  72. if (time->hours >= 24) return FALSE;
  73. if (time->month > 12 || time->month == 0) return FALSE;
  74. if (time->day > max_days[time->month - 1]) return FALSE;
  75. return TRUE;
  76. }
  77. sysret_t syscall_clock_get_time(clock_time_t *time)
  78. {
  79. if (get_previous_mode() != KERNEL_MODE && !check_usermode(time, sizeof(clock_time_t)))
  80. {
  81. return ERR_BADPTR;
  82. }
  83. EH_TRY
  84. {
  85. time->seconds = clock_current_time.seconds;
  86. time->minutes = clock_current_time.minutes;
  87. time->hours = clock_current_time.hours;
  88. time->day = clock_current_time.day;
  89. time->month = clock_current_time.month;
  90. time->year = clock_current_time.year;
  91. }
  92. EH_CATCH
  93. {
  94. EH_ESCAPE(return ERR_BADPTR);
  95. }
  96. EH_DONE;
  97. return ERR_SUCCESS;
  98. }
  99. sysret_t syscall_clock_set_time(clock_time_t *time)
  100. {
  101. clock_time_t safe_time = {0};
  102. if (get_previous_mode() == USER_MODE)
  103. {
  104. if (!check_usermode(time, sizeof(clock_time_t))) return ERR_BADPTR;
  105. EH_TRY safe_time = *time;
  106. EH_CATCH EH_ESCAPE(return ERR_BADPTR);
  107. EH_DONE;
  108. if (!check_privileges(PRIVILEGE_SET_TIME)) return ERR_FORBIDDEN;
  109. }
  110. else
  111. {
  112. safe_time = *time;
  113. }
  114. if (!clock_check_time(&safe_time)) return ERR_INVALID;
  115. byte_t seconds = safe_time.seconds;
  116. byte_t minutes = safe_time.minutes;
  117. byte_t hours = safe_time.hours;
  118. byte_t day = safe_time.day;
  119. byte_t month = safe_time.month;
  120. byte_t year = safe_time.year;
  121. if (!(clock_settings & CLOCK_BINARY_MODE))
  122. {
  123. hours = ((hours / 10) << 4) + (hours % 10);
  124. minutes = ((minutes / 10) << 4) + (minutes % 10);
  125. seconds = ((seconds / 10) << 4) + (seconds % 10);
  126. day = ((day / 10) << 4) + (day % 10);
  127. month = ((month / 10) << 4) + (month % 10);
  128. year = ((year / 10) << 4) + (year % 10);
  129. }
  130. if (!(clock_settings & CLOCK_24HOUR_MODE) && (hours > 12)) hours |= CLOCK_PM_BIT;
  131. critical_t critical;
  132. enter_critical(&critical);
  133. clock_current_time.seconds = safe_time.seconds;
  134. clock_current_time.minutes = safe_time.minutes;
  135. clock_current_time.hours = safe_time.hours;
  136. clock_current_time.day = safe_time.day;
  137. clock_current_time.month = safe_time.month;
  138. clock_current_time.year = safe_time.year;
  139. disable_nmi();
  140. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_SECONDS_REG);
  141. cpu_write_port_byte(CMOS_DATA_PORT, seconds);
  142. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_MINUTES_REG);
  143. cpu_write_port_byte(CMOS_DATA_PORT, minutes);
  144. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_HOURS_REG);
  145. cpu_write_port_byte(CMOS_DATA_PORT, hours);
  146. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_DAY_REG);
  147. cpu_write_port_byte(CMOS_DATA_PORT, day);
  148. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_MONTH_REG);
  149. cpu_write_port_byte(CMOS_DATA_PORT, month);
  150. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_YEAR_REG);
  151. cpu_write_port_byte(CMOS_DATA_PORT, year);
  152. enable_nmi();
  153. leave_critical(&critical);
  154. return ERR_SUCCESS;
  155. }
  156. void clock_init()
  157. {
  158. critical_t critical;
  159. enter_critical(&critical);
  160. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_STB_REG);
  161. clock_settings = cpu_read_port_byte(CMOS_DATA_PORT);
  162. if ((clock_settings & (CLOCK_ALARM_INT | CLOCK_PERIODIC_INT | CLOCK_UPDATE_INT)) != CLOCK_UPDATE_INT)
  163. {
  164. clock_settings &= ~(CLOCK_ALARM_INT | CLOCK_PERIODIC_INT);
  165. clock_settings |= CLOCK_UPDATE_INT;
  166. disable_nmi();
  167. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_STB_REG);
  168. cpu_write_port_byte(CMOS_DATA_PORT, clock_settings);
  169. enable_nmi();
  170. }
  171. register_irq_handler(CLOCK_IRQ, &clock_irq, FALSE);
  172. cpu_write_port_byte(CMOS_CMD_PORT, CMOS_RTC_STC_REG);
  173. cpu_read_port_byte(CMOS_DATA_PORT);
  174. leave_critical(&critical);
  175. }