clock.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * clock.c
  3. *
  4. * Copyright (C) 2018 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. #include <timer.h>
  25. #include <log.h>
  26. #define RTC_IRQ 8
  27. #define RTC_STA_UPDATING (1 << 7)
  28. #define RTC_HOURS_PM_BIT (1 << 7)
  29. #define RTC_STB_DST (1 << 0)
  30. #define RTC_STB_24HOUR (1 << 1)
  31. #define RTC_STB_BINARY (1 << 2)
  32. #define RTC_STB_SQUARE_WAVE (1 << 3)
  33. #define RTC_STB_UPDATE_INT (1 << 4)
  34. #define RTC_STB_ALARM_INT (1 << 5)
  35. #define RTC_STB_PERIODIC_INT (1 << 6)
  36. #define RTC_STB_DISABLE (1 << 7)
  37. #define RTC_SECONDS_REG 0x00
  38. #define RTC_MINUTES_REG 0x02
  39. #define RTC_HOURS_REG 0x04
  40. #define RTC_DAY_REG 0x07
  41. #define RTC_MONTH_REG 0x08
  42. #define RTC_YEAR_REG 0x09
  43. #define RTC_STA_REG 0x0A
  44. #define RTC_STB_REG 0x0B
  45. #define RTC_STC_REG 0x0C
  46. #define BCD_TO_BINARY(x) (((x) >> 4) * 10 + ((x) & 0x0F))
  47. typedef struct
  48. {
  49. byte_t second, minute, hour, day, month, year;
  50. } rtc_time_t;
  51. static clock_time_t clock_startup_timestamp = 0;
  52. static clock_time_t clock_adjustment = 0;
  53. static byte_t rtc_settings;
  54. static void read_rtc(rtc_time_t *time)
  55. {
  56. critical_t critical;
  57. enter_critical(&critical);
  58. cpu_write_port_byte(CMOS_CMD_PORT, RTC_STA_REG);
  59. for (;;) if (!(cpu_read_port_byte(CMOS_DATA_PORT) & RTC_STA_UPDATING)) break;
  60. cpu_write_port_byte(CMOS_CMD_PORT, RTC_SECONDS_REG);
  61. time->second = cpu_read_port_byte(CMOS_DATA_PORT);
  62. cpu_write_port_byte(CMOS_CMD_PORT, RTC_MINUTES_REG);
  63. time->minute = cpu_read_port_byte(CMOS_DATA_PORT);
  64. cpu_write_port_byte(CMOS_CMD_PORT, RTC_HOURS_REG);
  65. time->hour = cpu_read_port_byte(CMOS_DATA_PORT);
  66. cpu_write_port_byte(CMOS_CMD_PORT, RTC_DAY_REG);
  67. time->day = cpu_read_port_byte(CMOS_DATA_PORT);
  68. cpu_write_port_byte(CMOS_CMD_PORT, RTC_MONTH_REG);
  69. time->month = cpu_read_port_byte(CMOS_DATA_PORT);
  70. cpu_write_port_byte(CMOS_CMD_PORT, RTC_YEAR_REG);
  71. time->year = cpu_read_port_byte(CMOS_DATA_PORT);
  72. leave_critical(&critical);
  73. }
  74. sysret_t syscall_clock_get_time(clock_time_t *time)
  75. {
  76. if (get_previous_mode() != KERNEL_MODE && !check_usermode(time, sizeof(clock_time_t))) return ERR_BADPTR;
  77. int64_t microseconds = (int64_t)(timer_get_nanoseconds() / 1000ULL);
  78. EH_TRY
  79. {
  80. *time = clock_startup_timestamp + clock_adjustment + microseconds;
  81. }
  82. EH_CATCH
  83. {
  84. EH_ESCAPE(return ERR_BADPTR);
  85. }
  86. EH_DONE;
  87. return ERR_SUCCESS;
  88. }
  89. sysret_t syscall_clock_set_time(clock_time_t *time)
  90. {
  91. clock_time_t safe_time;
  92. if (get_previous_mode() == USER_MODE)
  93. {
  94. if (!check_usermode(time, sizeof(clock_time_t))) return ERR_BADPTR;
  95. EH_TRY safe_time = *time;
  96. EH_CATCH EH_ESCAPE(return ERR_BADPTR);
  97. EH_DONE;
  98. if (!check_privileges(PRIVILEGE_SET_TIME)) return ERR_FORBIDDEN;
  99. }
  100. else
  101. {
  102. safe_time = *time;
  103. }
  104. int64_t microseconds = (int64_t)(timer_get_nanoseconds() / 1000ULL);
  105. clock_time_t new_timestamp = safe_time;
  106. clock_time_t old_timestamp = clock_startup_timestamp + clock_adjustment + microseconds;
  107. clock_adjustment = new_timestamp - old_timestamp;
  108. // TODO: Update the RTC
  109. return ERR_SUCCESS;
  110. }
  111. void clock_init()
  112. {
  113. cpu_write_port_byte(CMOS_CMD_PORT, RTC_STB_REG);
  114. rtc_settings = cpu_read_port_byte(CMOS_DATA_PORT);
  115. rtc_time_t time;
  116. clock_time_t adjustment;
  117. for (;;)
  118. {
  119. rtc_time_t check;
  120. read_rtc(&check);
  121. adjustment = (clock_time_t)(timer_get_nanoseconds() / 1000ULL);
  122. read_rtc(&time);
  123. if (memcmp(&time, &check, sizeof(rtc_time_t))) break;
  124. }
  125. if (!(rtc_settings & RTC_STB_BINARY))
  126. {
  127. time.second = BCD_TO_BINARY(time.second);
  128. time.minute = BCD_TO_BINARY(time.minute);
  129. time.hour = BCD_TO_BINARY(time.hour & ~RTC_HOURS_PM_BIT) | (time.hour & RTC_HOURS_PM_BIT);
  130. time.day = BCD_TO_BINARY(time.day);
  131. time.month = BCD_TO_BINARY(time.month);
  132. time.year = BCD_TO_BINARY(time.year);
  133. }
  134. if (!(rtc_settings & RTC_STB_24HOUR))
  135. {
  136. time.hour = (time.hour & RTC_HOURS_PM_BIT) ? ((time.hour & ~RTC_HOURS_PM_BIT) % 12) + 12 : time.hour % 12;
  137. }
  138. TRACE("Current time: 20%02u-%02u-%02u %02u:%02u:%02u\n",
  139. time.year,
  140. time.month,
  141. time.day,
  142. time.hour,
  143. time.minute,
  144. time.second);
  145. int i;
  146. clock_startup_timestamp = 0;
  147. for (i = 1980; i < (int)time.year + 2000; i++)
  148. {
  149. clock_startup_timestamp += (!(i % 400) || (!(i % 4) && (i % 100))) ? 31622400000000LL : 31536000000000LL;
  150. }
  151. int month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  152. if (!(i % 400) || (!(i % 4) && (i % 100))) month_days[1]++;
  153. for (i = 1; i < time.month; i++)
  154. {
  155. clock_startup_timestamp += month_days[i - 1] * 86400000000LL;
  156. }
  157. clock_startup_timestamp += (time.day - 1) * 86400000000LL;
  158. clock_startup_timestamp += time.hour * 3600000000LL;
  159. clock_startup_timestamp += time.minute * 60000000LL;
  160. clock_startup_timestamp += time.second * 1000000LL;
  161. clock_startup_timestamp -= adjustment;
  162. TRACE("Startup timestamp: %lld\n", clock_startup_timestamp);
  163. }