Diff for /qemu/hw/mc146818rtc.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2018/04/24 16:48:33 version 1.1.1.4, 2018/04/24 16:52:53
Line 26 Line 26
 #include "sysemu.h"  #include "sysemu.h"
 #include "pc.h"  #include "pc.h"
 #include "isa.h"  #include "isa.h"
   #include "hpet_emul.h"
   
 //#define DEBUG_CMOS  //#define DEBUG_CMOS
   
Line 53 Line 54
 #define REG_B_PIE 0x40  #define REG_B_PIE 0x40
 #define REG_B_AIE 0x20  #define REG_B_AIE 0x20
 #define REG_B_UIE 0x10  #define REG_B_UIE 0x10
   #define REG_B_DM  0x04
   
 struct RTCState {  struct RTCState {
     uint8_t cmos_data[128];      uint8_t cmos_data[128];
     uint8_t cmos_index;      uint8_t cmos_index;
     struct tm current_tm;      struct tm current_tm;
       int base_year;
     qemu_irq irq;      qemu_irq irq;
     target_phys_addr_t base;  
     int it_shift;      int it_shift;
     /* periodic timer */      /* periodic timer */
     QEMUTimer *periodic_timer;      QEMUTimer *periodic_timer;
     int64_t next_periodic_time;      int64_t next_periodic_time;
     /* second update */      /* second update */
     int64_t next_second_time;      int64_t next_second_time;
   #ifdef TARGET_I386
       uint32_t irq_coalesced;
       uint32_t period;
   #endif
     QEMUTimer *second_timer;      QEMUTimer *second_timer;
     QEMUTimer *second_timer2;      QEMUTimer *second_timer2;
 };  };
   
   static void rtc_irq_raise(qemu_irq irq) {
       /* When HPET is operating in legacy mode, RTC interrupts are disabled
        * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
        * mode is established while interrupt is raised. We want it to
        * be lowered in any case
        */
   #if defined TARGET_I386 || defined TARGET_X86_64
       if (!hpet_in_legacy_mode())
   #endif
           qemu_irq_raise(irq);
   }
   
 static void rtc_set_time(RTCState *s);  static void rtc_set_time(RTCState *s);
 static void rtc_copy_date(RTCState *s);  static void rtc_copy_date(RTCState *s);
   
Line 79  static void rtc_timer_update(RTCState *s Line 97  static void rtc_timer_update(RTCState *s
     int64_t cur_clock, next_irq_clock;      int64_t cur_clock, next_irq_clock;
   
     period_code = s->cmos_data[RTC_REG_A] & 0x0f;      period_code = s->cmos_data[RTC_REG_A] & 0x0f;
     if (period_code != 0 &&  #if defined TARGET_I386 || defined TARGET_X86_64
         (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {      /* disable periodic timer if hpet is in legacy mode, since interrupts are
        * disabled anyway.
        */
       if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) {
   #else
       if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
   #endif
         if (period_code <= 2)          if (period_code <= 2)
             period_code += 7;              period_code += 7;
         /* period in 32 Khz cycles */          /* period in 32 Khz cycles */
         period = 1 << (period_code - 1);          period = 1 << (period_code - 1);
   #ifdef TARGET_I386
           if(period != s->period)
               s->irq_coalesced = (s->irq_coalesced * s->period) / period;
           s->period = period;
   #endif
         /* compute 32 khz clock */          /* compute 32 khz clock */
         cur_clock = muldiv64(current_time, 32768, ticks_per_sec);          cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
         next_irq_clock = (cur_clock & ~(period - 1)) + period;          next_irq_clock = (cur_clock & ~(period - 1)) + period;
         s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;          s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
         qemu_mod_timer(s->periodic_timer, s->next_periodic_time);          qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
     } else {      } else {
   #ifdef TARGET_I386
           s->irq_coalesced = 0;
   #endif
         qemu_del_timer(s->periodic_timer);          qemu_del_timer(s->periodic_timer);
     }      }
 }  }
Line 100  static void rtc_periodic_timer(void *opa Line 132  static void rtc_periodic_timer(void *opa
     RTCState *s = opaque;      RTCState *s = opaque;
   
     rtc_timer_update(s, s->next_periodic_time);      rtc_timer_update(s, s->next_periodic_time);
   #ifdef TARGET_I386
       if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) {
           s->irq_coalesced++;
           return;
       }
   #endif
     s->cmos_data[RTC_REG_C] |= 0xc0;      s->cmos_data[RTC_REG_C] |= 0xc0;
     qemu_irq_raise(s->irq);      rtc_irq_raise(s->irq);
 }  }
   
 static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)  static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
Line 168  static void cmos_ioport_write(void *opaq Line 206  static void cmos_ioport_write(void *opaq
   
 static inline int to_bcd(RTCState *s, int a)  static inline int to_bcd(RTCState *s, int a)
 {  {
     if (s->cmos_data[RTC_REG_B] & 0x04) {      if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
         return a;          return a;
     } else {      } else {
         return ((a / 10) << 4) | (a % 10);          return ((a / 10) << 4) | (a % 10);
Line 177  static inline int to_bcd(RTCState *s, in Line 215  static inline int to_bcd(RTCState *s, in
   
 static inline int from_bcd(RTCState *s, int a)  static inline int from_bcd(RTCState *s, int a)
 {  {
     if (s->cmos_data[RTC_REG_B] & 0x04) {      if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
         return a;          return a;
     } else {      } else {
         return ((a >> 4) * 10) + (a & 0x0f);          return ((a >> 4) * 10) + (a & 0x0f);
Line 195  static void rtc_set_time(RTCState *s) Line 233  static void rtc_set_time(RTCState *s)
         (s->cmos_data[RTC_HOURS] & 0x80)) {          (s->cmos_data[RTC_HOURS] & 0x80)) {
         tm->tm_hour += 12;          tm->tm_hour += 12;
     }      }
     tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);      tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
     tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);      tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
     tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;      tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
     tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;      tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
 }  }
   
 static void rtc_copy_date(RTCState *s)  static void rtc_copy_date(RTCState *s)
 {  {
     const struct tm *tm = &s->current_tm;      const struct tm *tm = &s->current_tm;
       int year;
   
     s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);      s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
     s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);      s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
Line 216  static void rtc_copy_date(RTCState *s) Line 255  static void rtc_copy_date(RTCState *s)
         if (tm->tm_hour >= 12)          if (tm->tm_hour >= 12)
             s->cmos_data[RTC_HOURS] |= 0x80;              s->cmos_data[RTC_HOURS] |= 0x80;
     }      }
     s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);      s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday + 1);
     s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);      s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
     s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);      s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
     s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);      year = (tm->tm_year - s->base_year) % 100;
       if (year < 0)
           year += 100;
       s->cmos_data[RTC_YEAR] = to_bcd(s, year);
 }  }
   
 /* month is between 0 and 11. */  /* month is between 0 and 11. */
Line 320  static void rtc_update_second2(void *opa Line 362  static void rtc_update_second2(void *opa
              s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {               s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
   
             s->cmos_data[RTC_REG_C] |= 0xa0;              s->cmos_data[RTC_REG_C] |= 0xa0;
             qemu_irq_raise(s->irq);              rtc_irq_raise(s->irq);
         }          }
     }      }
   
     /* update ended interrupt */      /* update ended interrupt */
     if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {      if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
         s->cmos_data[RTC_REG_C] |= 0x90;          s->cmos_data[RTC_REG_C] |= 0x90;
         qemu_irq_raise(s->irq);          rtc_irq_raise(s->irq);
     }      }
   
     /* clear update in progress bit */      /* clear update in progress bit */
Line 360  static uint32_t cmos_ioport_read(void *o Line 402  static uint32_t cmos_ioport_read(void *o
         case RTC_REG_C:          case RTC_REG_C:
             ret = s->cmos_data[s->cmos_index];              ret = s->cmos_data[s->cmos_index];
             qemu_irq_lower(s->irq);              qemu_irq_lower(s->irq);
   #ifdef TARGET_I386
               if(s->irq_coalesced) {
                   apic_reset_irq_delivered();
                   qemu_irq_raise(s->irq);
                   if (apic_get_irq_delivered())
                       s->irq_coalesced--;
                   break;
               }
   #endif
             s->cmos_data[RTC_REG_C] = 0x00;              s->cmos_data[RTC_REG_C] = 0x00;
             break;              break;
         default:          default:
Line 392  void rtc_set_date(RTCState *s, const str Line 443  void rtc_set_date(RTCState *s, const str
   
 static void rtc_set_date_from_host(RTCState *s)  static void rtc_set_date_from_host(RTCState *s)
 {  {
     time_t ti;      struct tm tm;
     struct tm *tm;  
     int val;      int val;
   
     /* set the CMOS date */      /* set the CMOS date */
     if (rtc_start_date == -1) {      qemu_get_timedate(&tm, 0);
         time(&ti);      rtc_set_date(s, &tm);
         if (rtc_utc)  
             tm = gmtime(&ti);  
         else  
             tm = localtime(&ti);  
     } else {  
         ti = rtc_start_date;  
         tm = gmtime(&ti);  
     }  
     rtc_set_date(s, tm);  
   
     val = to_bcd(s, (tm->tm_year / 100) + 19);      val = to_bcd(s, (tm.tm_year / 100) + 19);
     rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);      rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
     rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);      rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
 }  }
Line 464  static int rtc_load(QEMUFile *f, void *o Line 505  static int rtc_load(QEMUFile *f, void *o
     return 0;      return 0;
 }  }
   
 RTCState *rtc_init(int base, qemu_irq irq)  #ifdef TARGET_I386
   static void rtc_save_td(QEMUFile *f, void *opaque)
   {
       RTCState *s = opaque;
   
       qemu_put_be32(f, s->irq_coalesced);
       qemu_put_be32(f, s->period);
   }
   
   static int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
   {
       RTCState *s = opaque;
   
       if (version_id != 1)
           return -EINVAL;
   
       s->irq_coalesced = qemu_get_be32(f);
       s->period = qemu_get_be32(f);
       return 0;
   }
   #endif
   
   RTCState *rtc_init(int base, qemu_irq irq, int base_year)
 {  {
     RTCState *s;      RTCState *s;
   
     s = qemu_mallocz(sizeof(RTCState));      s = qemu_mallocz(sizeof(RTCState));
     if (!s)  
         return NULL;  
   
     s->irq = irq;      s->irq = irq;
     s->cmos_data[RTC_REG_A] = 0x26;      s->cmos_data[RTC_REG_A] = 0x26;
Line 478  RTCState *rtc_init(int base, qemu_irq ir Line 539  RTCState *rtc_init(int base, qemu_irq ir
     s->cmos_data[RTC_REG_C] = 0x00;      s->cmos_data[RTC_REG_C] = 0x00;
     s->cmos_data[RTC_REG_D] = 0x80;      s->cmos_data[RTC_REG_D] = 0x80;
   
       s->base_year = base_year;
     rtc_set_date_from_host(s);      rtc_set_date_from_host(s);
   
     s->periodic_timer = qemu_new_timer(vm_clock,      s->periodic_timer = qemu_new_timer(vm_clock,
Line 494  RTCState *rtc_init(int base, qemu_irq ir Line 556  RTCState *rtc_init(int base, qemu_irq ir
     register_ioport_read(base, 2, 1, cmos_ioport_read, s);      register_ioport_read(base, 2, 1, cmos_ioport_read, s);
   
     register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);      register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
   #ifdef TARGET_I386
       if (rtc_td_hack)
           register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
   #endif
     return s;      return s;
 }  }
   
Line 502  static uint32_t cmos_mm_readb (void *opa Line 568  static uint32_t cmos_mm_readb (void *opa
 {  {
     RTCState *s = opaque;      RTCState *s = opaque;
   
     return cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;      return cmos_ioport_read(s, addr >> s->it_shift) & 0xFF;
 }  }
   
 static void cmos_mm_writeb (void *opaque,  static void cmos_mm_writeb (void *opaque,
Line 510  static void cmos_mm_writeb (void *opaque Line 576  static void cmos_mm_writeb (void *opaque
 {  {
     RTCState *s = opaque;      RTCState *s = opaque;
   
     cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);      cmos_ioport_write(s, addr >> s->it_shift, value & 0xFF);
 }  }
   
 static uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)  static uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
Line 518  static uint32_t cmos_mm_readw (void *opa Line 584  static uint32_t cmos_mm_readw (void *opa
     RTCState *s = opaque;      RTCState *s = opaque;
     uint32_t val;      uint32_t val;
   
     val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;      val = cmos_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
 #ifdef TARGET_WORDS_BIGENDIAN  #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap16(val);      val = bswap16(val);
 #endif  #endif
Line 532  static void cmos_mm_writew (void *opaque Line 598  static void cmos_mm_writew (void *opaque
 #ifdef TARGET_WORDS_BIGENDIAN  #ifdef TARGET_WORDS_BIGENDIAN
     value = bswap16(value);      value = bswap16(value);
 #endif  #endif
     cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);      cmos_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
 }  }
   
 static uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)  static uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
Line 540  static uint32_t cmos_mm_readl (void *opa Line 606  static uint32_t cmos_mm_readl (void *opa
     RTCState *s = opaque;      RTCState *s = opaque;
     uint32_t val;      uint32_t val;
   
     val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift);      val = cmos_ioport_read(s, addr >> s->it_shift);
 #ifdef TARGET_WORDS_BIGENDIAN  #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap32(val);      val = bswap32(val);
 #endif  #endif
Line 554  static void cmos_mm_writel (void *opaque Line 620  static void cmos_mm_writel (void *opaque
 #ifdef TARGET_WORDS_BIGENDIAN  #ifdef TARGET_WORDS_BIGENDIAN
     value = bswap32(value);      value = bswap32(value);
 #endif  #endif
     cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value);      cmos_ioport_write(s, addr >> s->it_shift, value);
 }  }
   
 static CPUReadMemoryFunc *rtc_mm_read[] = {  static CPUReadMemoryFunc *rtc_mm_read[] = {
Line 569  static CPUWriteMemoryFunc *rtc_mm_write[ Line 635  static CPUWriteMemoryFunc *rtc_mm_write[
     &cmos_mm_writel,      &cmos_mm_writel,
 };  };
   
 RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)  RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
                         int base_year)
 {  {
     RTCState *s;      RTCState *s;
     int io_memory;      int io_memory;
   
     s = qemu_mallocz(sizeof(RTCState));      s = qemu_mallocz(sizeof(RTCState));
     if (!s)  
         return NULL;  
   
     s->irq = irq;      s->irq = irq;
     s->cmos_data[RTC_REG_A] = 0x26;      s->cmos_data[RTC_REG_A] = 0x26;
     s->cmos_data[RTC_REG_B] = 0x02;      s->cmos_data[RTC_REG_B] = 0x02;
     s->cmos_data[RTC_REG_C] = 0x00;      s->cmos_data[RTC_REG_C] = 0x00;
     s->cmos_data[RTC_REG_D] = 0x80;      s->cmos_data[RTC_REG_D] = 0x80;
     s->base = base;  
   
       s->base_year = base_year;
     rtc_set_date_from_host(s);      rtc_set_date_from_host(s);
   
     s->periodic_timer = qemu_new_timer(vm_clock,      s->periodic_timer = qemu_new_timer(vm_clock,
Line 601  RTCState *rtc_mm_init(target_phys_addr_t Line 666  RTCState *rtc_mm_init(target_phys_addr_t
     cpu_register_physical_memory(base, 2 << it_shift, io_memory);      cpu_register_physical_memory(base, 2 << it_shift, io_memory);
   
     register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);      register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
   #ifdef TARGET_I386
       if (rtc_td_hack)
           register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
   #endif
     return s;      return s;
 }  }

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


unix.superglobalmegacorp.com