2
0

rtc.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * RTC configuration and clock read
  3. *
  4. * Copyright (c) 2003-2020 QEMU contributors
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "qemu/cutils.h"
  26. #include "qapi/error.h"
  27. #include "qemu/error-report.h"
  28. #include "qemu/option.h"
  29. #include "qemu/timer.h"
  30. #include "qom/object.h"
  31. #include "system/replay.h"
  32. #include "system/system.h"
  33. #include "system/rtc.h"
  34. #include "hw/rtc/mc146818rtc.h"
  35. static enum {
  36. RTC_BASE_UTC,
  37. RTC_BASE_LOCALTIME,
  38. RTC_BASE_DATETIME,
  39. } rtc_base_type = RTC_BASE_UTC;
  40. static time_t rtc_ref_start_datetime;
  41. static int rtc_realtime_clock_offset; /* used only with QEMU_CLOCK_REALTIME */
  42. static int rtc_host_datetime_offset = -1; /* valid & used only with
  43. RTC_BASE_DATETIME */
  44. QEMUClockType rtc_clock;
  45. /***********************************************************/
  46. /* RTC reference time/date access */
  47. static time_t qemu_ref_timedate(QEMUClockType clock)
  48. {
  49. time_t value = qemu_clock_get_ms(clock) / 1000;
  50. switch (clock) {
  51. case QEMU_CLOCK_REALTIME:
  52. value -= rtc_realtime_clock_offset;
  53. /* fall through */
  54. case QEMU_CLOCK_VIRTUAL:
  55. value += rtc_ref_start_datetime;
  56. break;
  57. case QEMU_CLOCK_HOST:
  58. if (rtc_base_type == RTC_BASE_DATETIME) {
  59. value -= rtc_host_datetime_offset;
  60. }
  61. break;
  62. default:
  63. g_assert_not_reached();
  64. }
  65. return value;
  66. }
  67. void qemu_get_timedate(struct tm *tm, time_t offset)
  68. {
  69. time_t ti = qemu_ref_timedate(rtc_clock);
  70. ti += offset;
  71. switch (rtc_base_type) {
  72. case RTC_BASE_DATETIME:
  73. case RTC_BASE_UTC:
  74. gmtime_r(&ti, tm);
  75. break;
  76. case RTC_BASE_LOCALTIME:
  77. localtime_r(&ti, tm);
  78. break;
  79. }
  80. }
  81. time_t qemu_timedate_diff(struct tm *tm)
  82. {
  83. time_t seconds;
  84. switch (rtc_base_type) {
  85. case RTC_BASE_DATETIME:
  86. case RTC_BASE_UTC:
  87. seconds = mktimegm(tm);
  88. break;
  89. case RTC_BASE_LOCALTIME:
  90. {
  91. struct tm tmp = *tm;
  92. tmp.tm_isdst = -1; /* use timezone to figure it out */
  93. seconds = mktime(&tmp);
  94. break;
  95. }
  96. default:
  97. abort();
  98. }
  99. return seconds - qemu_ref_timedate(QEMU_CLOCK_HOST);
  100. }
  101. static void configure_rtc_base_datetime(const char *startdate)
  102. {
  103. time_t rtc_start_datetime;
  104. struct tm tm;
  105. if (sscanf(startdate, "%d-%d-%dT%d:%d:%d", &tm.tm_year, &tm.tm_mon,
  106. &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) {
  107. /* OK */
  108. } else if (sscanf(startdate, "%d-%d-%d",
  109. &tm.tm_year, &tm.tm_mon, &tm.tm_mday) == 3) {
  110. tm.tm_hour = 0;
  111. tm.tm_min = 0;
  112. tm.tm_sec = 0;
  113. } else {
  114. goto date_fail;
  115. }
  116. tm.tm_year -= 1900;
  117. tm.tm_mon--;
  118. rtc_start_datetime = mktimegm(&tm);
  119. if (rtc_start_datetime == -1) {
  120. date_fail:
  121. error_report("invalid datetime format");
  122. error_printf("valid formats: "
  123. "'2006-06-17T16:01:21' or '2006-06-17'\n");
  124. exit(1);
  125. }
  126. rtc_host_datetime_offset = rtc_ref_start_datetime - rtc_start_datetime;
  127. rtc_ref_start_datetime = rtc_start_datetime;
  128. }
  129. void configure_rtc(QemuOpts *opts)
  130. {
  131. const char *value;
  132. /* Set defaults */
  133. rtc_clock = QEMU_CLOCK_HOST;
  134. rtc_ref_start_datetime = qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000;
  135. rtc_realtime_clock_offset = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000;
  136. value = qemu_opt_get(opts, "base");
  137. if (value) {
  138. if (!strcmp(value, "utc")) {
  139. rtc_base_type = RTC_BASE_UTC;
  140. } else if (!strcmp(value, "localtime")) {
  141. rtc_base_type = RTC_BASE_LOCALTIME;
  142. replay_add_blocker("-rtc base=localtime");
  143. } else {
  144. rtc_base_type = RTC_BASE_DATETIME;
  145. configure_rtc_base_datetime(value);
  146. }
  147. }
  148. value = qemu_opt_get(opts, "clock");
  149. if (value) {
  150. if (!strcmp(value, "host")) {
  151. rtc_clock = QEMU_CLOCK_HOST;
  152. } else if (!strcmp(value, "rt")) {
  153. rtc_clock = QEMU_CLOCK_REALTIME;
  154. } else if (!strcmp(value, "vm")) {
  155. rtc_clock = QEMU_CLOCK_VIRTUAL;
  156. } else {
  157. error_report("invalid option value '%s'", value);
  158. exit(1);
  159. }
  160. }
  161. value = qemu_opt_get(opts, "driftfix");
  162. if (value) {
  163. if (!strcmp(value, "slew")) {
  164. object_register_sugar_prop(TYPE_MC146818_RTC,
  165. "lost_tick_policy",
  166. "slew",
  167. false);
  168. if (!object_class_by_name(TYPE_MC146818_RTC)) {
  169. warn_report("driftfix 'slew' is not available with this machine");
  170. }
  171. } else if (!strcmp(value, "none")) {
  172. /* discard is default */
  173. } else {
  174. error_report("invalid option value '%s'", value);
  175. exit(1);
  176. }
  177. }
  178. }