コード例 #1
0
ファイル: rtc.c プロジェクト: 0day-ci/xen
static void rtc_set_time(RTCState *s)
{
    struct tm *tm = &s->current_tm;
    struct domain *d = vrtc_domain(s);
    unsigned long before, after; /* XXX s_time_t */
      
    ASSERT(spin_is_locked(&s->lock));

    before = mktime(get_year(tm->tm_year), tm->tm_mon + 1, tm->tm_mday,
		    tm->tm_hour, tm->tm_min, tm->tm_sec);
    
    tm->tm_sec = from_bcd(s, s->hw.cmos_data[RTC_SECONDS]);
    tm->tm_min = from_bcd(s, s->hw.cmos_data[RTC_MINUTES]);
    tm->tm_hour = convert_hour(s, s->hw.cmos_data[RTC_HOURS]);
    tm->tm_wday = from_bcd(s, s->hw.cmos_data[RTC_DAY_OF_WEEK]);
    tm->tm_mday = from_bcd(s, s->hw.cmos_data[RTC_DAY_OF_MONTH]);
    tm->tm_mon = from_bcd(s, s->hw.cmos_data[RTC_MONTH]) - 1;
    tm->tm_year = from_bcd(s, s->hw.cmos_data[RTC_YEAR]) + 100;

    after = mktime(get_year(tm->tm_year), tm->tm_mon + 1, tm->tm_mday,
                   tm->tm_hour, tm->tm_min, tm->tm_sec);

    /* We use the guest's setting of the RTC to define the local-time 
     * offset for this domain. */
    d->time_offset_seconds += (after - before);
    update_domain_wallclock_time(d);
    /* Also tell qemu-dm about it so it will be remembered for next boot. */
    send_timeoffset_req(after - before);
}
コード例 #2
0
ファイル: mc146818rtc.c プロジェクト: 01org/KVMGT-qemu
static uint64_t get_next_alarm(RTCState *s)
{
    int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec;
    int32_t hour, min, sec;

    rtc_update_time(s);

    alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]);
    alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]);
    alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]);
    alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour);

    cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
    cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
    cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]);
    cur_hour = convert_hour(s, cur_hour);

    if (alarm_hour == -1) {
        alarm_hour = cur_hour;
        if (alarm_min == -1) {
            alarm_min = cur_min;
            if (alarm_sec == -1) {
                alarm_sec = cur_sec + 1;
            } else if (cur_sec > alarm_sec) {
                alarm_min++;
            }
        } else if (cur_min == alarm_min) {
            if (alarm_sec == -1) {
                alarm_sec = cur_sec + 1;
            } else {
                if (cur_sec > alarm_sec) {
                    alarm_hour++;
                }
            }
            if (alarm_sec == SEC_PER_MIN) {
                /* wrap to next hour, minutes is not in don't care mode */
                alarm_sec = 0;
                alarm_hour++;
            }
        } else if (cur_min > alarm_min) {
            alarm_hour++;
        }
    } else if (cur_hour == alarm_hour) {
        if (alarm_min == -1) {
            alarm_min = cur_min;
            if (alarm_sec == -1) {
                alarm_sec = cur_sec + 1;
            } else if (cur_sec > alarm_sec) {
                alarm_min++;
            }

            if (alarm_sec == SEC_PER_MIN) {
                alarm_sec = 0;
                alarm_min++;
            }
            /* wrap to next day, hour is not in don't care mode */
            alarm_min %= MIN_PER_HOUR;
        } else if (cur_min == alarm_min) {
            if (alarm_sec == -1) {
                alarm_sec = cur_sec + 1;
            }
            /* wrap to next day, hours+minutes not in don't care mode */
            alarm_sec %= SEC_PER_MIN;
        }
    }

    /* values that are still don't care fire at the next min/sec */
    if (alarm_min == -1) {
        alarm_min = 0;
    }
    if (alarm_sec == -1) {
        alarm_sec = 0;
    }

    /* keep values in range */
    if (alarm_sec == SEC_PER_MIN) {
        alarm_sec = 0;
        alarm_min++;
    }
    if (alarm_min == MIN_PER_HOUR) {
        alarm_min = 0;
        alarm_hour++;
    }
    alarm_hour %= HOUR_PER_DAY;

    hour = alarm_hour - cur_hour;
    min = hour * MIN_PER_HOUR + alarm_min - cur_min;
    sec = min * SEC_PER_MIN + alarm_sec - cur_sec;
    return sec <= 0 ? sec + SEC_PER_DAY : sec;
}
コード例 #3
0
ファイル: rtc.c プロジェクト: 0day-ci/xen
/* handle alarm timer */
static void alarm_timer_update(RTCState *s)
{
    uint64_t next_update_time, next_alarm_sec;
    uint64_t expire_time;
    int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec;
    int32_t hour, min;
    struct domain *d = vrtc_domain(s);

    ASSERT(spin_is_locked(&s->lock));

    stop_timer(&s->alarm_timer);

    if (!(s->hw.cmos_data[RTC_REG_C] & RTC_AF) &&
            !(s->hw.cmos_data[RTC_REG_B] & RTC_SET))
    {
        s->current_tm = gmtime(get_localtime(d));
        rtc_copy_date(s);

        alarm_sec = from_bcd(s, s->hw.cmos_data[RTC_SECONDS_ALARM]);
        alarm_min = from_bcd(s, s->hw.cmos_data[RTC_MINUTES_ALARM]);
        alarm_hour = convert_hour(s, s->hw.cmos_data[RTC_HOURS_ALARM]);

        cur_sec = from_bcd(s, s->hw.cmos_data[RTC_SECONDS]);
        cur_min = from_bcd(s, s->hw.cmos_data[RTC_MINUTES]);
        cur_hour = convert_hour(s, s->hw.cmos_data[RTC_HOURS]);

        next_update_time = USEC_PER_SEC - (get_localtime_us(d) % USEC_PER_SEC);
        next_update_time = next_update_time * NS_PER_USEC + NOW();

        if ((s->hw.cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0)
        {
            if ((s->hw.cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0)
            {
                if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                    next_alarm_sec = 1;
                else if (cur_sec < alarm_sec)
                    next_alarm_sec = alarm_sec - cur_sec;
                else
                    next_alarm_sec = alarm_sec + SEC_PER_MIN - cur_sec;
            }
            else
            {
                if (cur_min < alarm_min)
                {
                    min = alarm_min - cur_min;
                    next_alarm_sec = min * SEC_PER_MIN - cur_sec;
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec += 0;
                    else
                        next_alarm_sec += alarm_sec;
                }
                else if (cur_min == alarm_min)
                {
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec = 1;
                    else if (cur_sec < alarm_sec)
                        next_alarm_sec = alarm_sec - cur_sec;
                    else
                    {
                        min = alarm_min + MIN_PER_HOUR - cur_min;
                        next_alarm_sec =
                            alarm_sec + min * SEC_PER_MIN - cur_sec;
                    }
                }
                else
                {
                    min = alarm_min + MIN_PER_HOUR - cur_min;
                    next_alarm_sec = min * SEC_PER_MIN - cur_sec;
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec += 0;
                    else
                        next_alarm_sec += alarm_sec;
                }
            }
        }
        else
        {
            if (cur_hour < alarm_hour)
            {
                hour = alarm_hour - cur_hour;
                next_alarm_sec = hour * SEC_PER_HOUR -
                    cur_min * SEC_PER_MIN - cur_sec;
                if ((s->hw.cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0)
                {
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec += 0;
                    else
                        next_alarm_sec += alarm_sec;
                }
                else
                {
                    next_alarm_sec += alarm_min * SEC_PER_MIN;
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec += 0;
                    else
                        next_alarm_sec += alarm_sec;
                }
            }
            else if (cur_hour == alarm_hour)
            {
                if ((s->hw.cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0)
                {
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec = 1;
                    else if (cur_sec < alarm_sec)
                        next_alarm_sec = alarm_sec - cur_sec;
                    else
                        next_alarm_sec = alarm_sec + SEC_PER_MIN - cur_sec;
                }
                else if (cur_min < alarm_min)
                {
                    min = alarm_min - cur_min;
                    next_alarm_sec = min * SEC_PER_MIN - cur_sec;
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec += 0;
                    else
                        next_alarm_sec += alarm_sec;
                }
                else if (cur_min == alarm_min)
                {
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec = 1;
                    else if (cur_sec < alarm_sec)
                        next_alarm_sec = alarm_sec - cur_sec;
                    else
                    {
                        hour = alarm_hour + HOUR_PER_DAY - cur_hour;
                        next_alarm_sec = hour * SEC_PER_HOUR -
                            cur_min * SEC_PER_MIN - cur_sec;
                        next_alarm_sec += alarm_min * SEC_PER_MIN + alarm_sec;
                    }
                }
                else
                {
                    hour = alarm_hour + HOUR_PER_DAY - cur_hour;
                    next_alarm_sec = hour * SEC_PER_HOUR -
                        cur_min * SEC_PER_MIN - cur_sec;
                    next_alarm_sec += alarm_min * SEC_PER_MIN;
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec += 0;
                    else
                        next_alarm_sec += alarm_sec;
                }
            }
            else
            {
                hour = alarm_hour + HOUR_PER_DAY - cur_hour;
                next_alarm_sec = hour * SEC_PER_HOUR -
                    cur_min * SEC_PER_MIN - cur_sec;
                if ((s->hw.cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0)
                {
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec += 0;
                    else
                        next_alarm_sec += alarm_sec;
                }
                else
                {
                    next_alarm_sec += alarm_min * SEC_PER_MIN;
                    if ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0)
                        next_alarm_sec += 0;
                    else
                        next_alarm_sec += alarm_sec;
                }
            }
        }
        expire_time = (next_alarm_sec - 1) * NS_PER_SEC + next_update_time;
        /* release lock before set timer */
        spin_unlock(&s->lock);
        set_timer(&s->alarm_timer, expire_time);
        /* fetch lock again */
        spin_lock(&s->lock);
    }
}