mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-07 12:29:48 +00:00
DM: use acrn_timer api to emulate rtc
Current RTC emulation is based on sigevent mechanism, replace with acrn_timer API which based on timerfd/epoll mechanism to avoid potential resource accessing conflict in the async thread. Tracked-On: #1489 Signed-off-by: Victor Sun <victor.sun@intel.com> Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com> Acked-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
parent
8fdea84a63
commit
0e897c0a6a
@ -31,19 +31,14 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <sys/signalfd.h>
|
|
||||||
|
|
||||||
#include "vmmapi.h"
|
#include "vmmapi.h"
|
||||||
#include "inout.h"
|
#include "inout.h"
|
||||||
#include "mc146818rtc.h"
|
#include "mc146818rtc.h"
|
||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "mevent.h"
|
#include "mevent.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
/* #define DEBUG_RTC */
|
/* #define DEBUG_RTC */
|
||||||
#ifdef DEBUG_RTC
|
#ifdef DEBUG_RTC
|
||||||
@ -76,10 +71,8 @@ struct rtcdev {
|
|||||||
struct vrtc {
|
struct vrtc {
|
||||||
struct vmctx *vm;
|
struct vmctx *vm;
|
||||||
pthread_mutex_t mtx;
|
pthread_mutex_t mtx;
|
||||||
int signal_fd;
|
struct acrn_timer update_timer; /* timer for update interrupt */
|
||||||
struct mevent *mevp;
|
struct acrn_timer periodic_timer; /* timer for periodic interrupt */
|
||||||
timer_t periodic_timer_id; /*periodic timer id*/
|
|
||||||
timer_t update_timer_id; /*update timer id*/
|
|
||||||
u_int addr; /* RTC register to read or write */
|
u_int addr; /* RTC register to read or write */
|
||||||
time_t base_uptime;
|
time_t base_uptime;
|
||||||
time_t base_rtctime;
|
time_t base_rtctime;
|
||||||
@ -576,34 +569,17 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vrtc_create_timer(timer_t *timer_id, time_t sec, time_t nsec)
|
vrtc_start_timer(struct acrn_timer *timer, time_t sec, time_t nsec)
|
||||||
{
|
{
|
||||||
struct sigevent sigevt;
|
|
||||||
struct itimerspec ts;
|
struct itimerspec ts;
|
||||||
|
|
||||||
memset(&sigevt, 0, sizeof(struct sigevent));
|
|
||||||
memset(&ts, 0, sizeof(struct itimerspec));
|
|
||||||
|
|
||||||
/* there is no glibc wrapper for gettid */
|
|
||||||
sigevt._sigev_un._tid = syscall(SYS_gettid);
|
|
||||||
sigevt.sigev_value.sival_ptr = timer_id;
|
|
||||||
sigevt.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
|
|
||||||
sigevt.sigev_signo = VRTC_TIMER_SIGNO;
|
|
||||||
|
|
||||||
assert(timer_create(CLOCK_REALTIME, &sigevt, timer_id) == 0);
|
|
||||||
/*setting the interval time*/
|
/*setting the interval time*/
|
||||||
ts.it_interval.tv_sec = sec;
|
ts.it_interval.tv_sec = sec;
|
||||||
ts.it_interval.tv_nsec = nsec;
|
ts.it_interval.tv_nsec = nsec;
|
||||||
/*set the delay time it will be started when timer_setting*/
|
/*set the delay time it will be started when timer_setting*/
|
||||||
ts.it_value.tv_sec = sec;
|
ts.it_value.tv_sec = sec;
|
||||||
ts.it_value.tv_nsec = nsec;
|
ts.it_value.tv_nsec = nsec;
|
||||||
assert(timer_settime(*timer_id, 0, &ts, NULL) == 0);
|
assert(acrn_timer_settime(timer, &ts) == 0);
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
vrtc_delete_timer(timer_t timerid)
|
|
||||||
{
|
|
||||||
timer_delete(timerid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -814,15 +790,8 @@ vrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval)
|
|||||||
newfreq = vrtc_freq(vrtc);
|
newfreq = vrtc_freq(vrtc);
|
||||||
|
|
||||||
if (pintr_enabled(vrtc) && newfreq != oldfreq) {
|
if (pintr_enabled(vrtc) && newfreq != oldfreq) {
|
||||||
/*stop the previous timer*/
|
/*start the new periodic timer*/
|
||||||
if (vrtc->periodic_timer_id > 0) {
|
vrtc_start_timer(&vrtc->periodic_timer, 0, newfreq);
|
||||||
assert(timer_delete(vrtc->periodic_timer_id) == 0);
|
|
||||||
vrtc->periodic_timer_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*create the new periodic timer*/
|
|
||||||
vrtc_create_timer(&vrtc->periodic_timer_id, 0, newfreq);
|
|
||||||
assert(vrtc->periodic_timer_id > 0);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/*Nothing to do*/
|
/*Nothing to do*/
|
||||||
@ -875,15 +844,8 @@ vrtc_set_reg_a(struct vrtc *vrtc, uint8_t newval)
|
|||||||
newfreq = vrtc_freq(vrtc);
|
newfreq = vrtc_freq(vrtc);
|
||||||
|
|
||||||
if (pintr_enabled(vrtc) && newfreq != oldfreq) {
|
if (pintr_enabled(vrtc) && newfreq != oldfreq) {
|
||||||
/*stop the previous timer*/
|
/*start the new periodic timer*/
|
||||||
if (vrtc->periodic_timer_id > 0) {
|
vrtc_start_timer(&vrtc->periodic_timer, 0, newfreq);
|
||||||
assert(timer_delete(vrtc->periodic_timer_id) == 0);
|
|
||||||
vrtc->periodic_timer_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*create the new periodic timer*/
|
|
||||||
vrtc_create_timer(&vrtc->periodic_timer_id, 0, newfreq);
|
|
||||||
assert(vrtc->periodic_timer_id > 0);
|
|
||||||
} else {
|
} else {
|
||||||
/*Nothing to do*/
|
/*Nothing to do*/
|
||||||
}
|
}
|
||||||
@ -1108,41 +1070,6 @@ vrtc_enable_localtime(int l_time)
|
|||||||
local_time = l_time;
|
local_time = l_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
vrtc_handle_timer(int fd __attribute__((unused)),
|
|
||||||
enum ev_type t __attribute__((unused)),
|
|
||||||
void *arg)
|
|
||||||
{
|
|
||||||
struct vrtc *vrtc = arg;
|
|
||||||
struct signalfd_siginfo info;
|
|
||||||
timer_t *timer_id;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
len = read(vrtc->signal_fd, &info, sizeof(info));
|
|
||||||
if (len == -1 && errno == EAGAIN)
|
|
||||||
break;
|
|
||||||
if (len == -1) {
|
|
||||||
RTC_DEBUG("signal_fd read failed: error = %d\n",
|
|
||||||
errno);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (len != sizeof(info)) {
|
|
||||||
RTC_DEBUG("signal_fd read len error: len = %d\n",
|
|
||||||
len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
timer_id = (timer_t *)info.ssi_ptr;
|
|
||||||
if (*timer_id == vrtc->update_timer_id)
|
|
||||||
vrtc_update_timer(vrtc);
|
|
||||||
else if (*timer_id == vrtc->periodic_timer_id)
|
|
||||||
vrtc_periodic_timer(vrtc);
|
|
||||||
else
|
|
||||||
RTC_DEBUG("unsupported timer_id 0xlx\n", *timer_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
vrtc_init(struct vmctx *ctx)
|
vrtc_init(struct vmctx *ctx)
|
||||||
{
|
{
|
||||||
@ -1151,8 +1078,6 @@ vrtc_init(struct vmctx *ctx)
|
|||||||
int err;
|
int err;
|
||||||
struct rtcdev *rtc;
|
struct rtcdev *rtc;
|
||||||
time_t curtime;
|
time_t curtime;
|
||||||
sigset_t mask;
|
|
||||||
int flags;
|
|
||||||
struct inout_port rtc_addr, rtc_data;
|
struct inout_port rtc_addr, rtc_data;
|
||||||
|
|
||||||
vrtc = calloc(1, sizeof(struct vrtc));
|
vrtc = calloc(1, sizeof(struct vrtc));
|
||||||
@ -1226,30 +1151,14 @@ vrtc_init(struct vmctx *ctx)
|
|||||||
secs_to_rtc(curtime, vrtc, 0);
|
secs_to_rtc(curtime, vrtc, 0);
|
||||||
pthread_mutex_unlock(&vrtc->mtx);
|
pthread_mutex_unlock(&vrtc->mtx);
|
||||||
|
|
||||||
/*block VRTC_TIMER_SIGNO so it can be polled by signalfd*/
|
/* init periodic interrupt timer */
|
||||||
sigemptyset(&mask);
|
vrtc->periodic_timer.clockid = CLOCK_REALTIME;
|
||||||
sigaddset(&mask, VRTC_TIMER_SIGNO);
|
acrn_timer_init(&vrtc->periodic_timer, vrtc_periodic_timer, vrtc);
|
||||||
pthread_sigmask(SIG_BLOCK, &mask, NULL);
|
|
||||||
|
|
||||||
/*create signalfd*/
|
/* init update interrupt timer(1s)*/
|
||||||
vrtc->signal_fd = signalfd(-1, &mask, 0);
|
vrtc->update_timer.clockid = CLOCK_REALTIME;
|
||||||
assert(vrtc->signal_fd > 0);
|
acrn_timer_init(&vrtc->update_timer, vrtc_update_timer, vrtc);
|
||||||
|
vrtc_start_timer(&vrtc->update_timer, 1, 0);
|
||||||
/*set close-on-exec*/
|
|
||||||
flags = fcntl(vrtc->signal_fd, F_GETFD);
|
|
||||||
fcntl(vrtc->signal_fd, F_SETFD, flags | FD_CLOEXEC);
|
|
||||||
|
|
||||||
/*set non-block*/
|
|
||||||
flags = fcntl(vrtc->signal_fd, F_GETFL);
|
|
||||||
fcntl(vrtc->signal_fd, F_SETFL, flags | O_NONBLOCK);
|
|
||||||
|
|
||||||
vrtc->mevp = mevent_add(vrtc->signal_fd, EVF_READ,
|
|
||||||
vrtc_handle_timer, vrtc);
|
|
||||||
assert(vrtc->mevp != NULL);
|
|
||||||
|
|
||||||
/*create update interrupt timer(1s)*/
|
|
||||||
vrtc_create_timer(&vrtc->update_timer_id, 1, 0);
|
|
||||||
assert(vrtc->update_timer_id > 0);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1259,29 +1168,10 @@ vrtc_deinit(struct vmctx *ctx)
|
|||||||
{
|
{
|
||||||
struct vrtc *vrtc = ctx->vrtc;
|
struct vrtc *vrtc = ctx->vrtc;
|
||||||
struct inout_port iop;
|
struct inout_port iop;
|
||||||
sig_t prev_sig_handler;
|
|
||||||
|
|
||||||
/*delete timer*/
|
/*deinit acrn_timer*/
|
||||||
if (vrtc->update_timer_id > 0) {
|
acrn_timer_deinit(&vrtc->periodic_timer);
|
||||||
vrtc_delete_timer(vrtc->update_timer_id);
|
acrn_timer_deinit(&vrtc->update_timer);
|
||||||
vrtc->update_timer_id = (timer_t)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vrtc->periodic_timer_id > 0) {
|
|
||||||
vrtc_delete_timer(vrtc->periodic_timer_id);
|
|
||||||
vrtc->periodic_timer_id = (timer_t)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vrtc->mevp)
|
|
||||||
mevent_delete(vrtc->mevp);
|
|
||||||
|
|
||||||
if (vrtc->signal_fd > 0)
|
|
||||||
close(vrtc->signal_fd);
|
|
||||||
|
|
||||||
/*clear pending signals*/
|
|
||||||
prev_sig_handler = signal(VRTC_TIMER_SIGNO, SIG_IGN);
|
|
||||||
if (prev_sig_handler != SIG_ERR)
|
|
||||||
signal(VRTC_TIMER_SIGNO, prev_sig_handler);
|
|
||||||
|
|
||||||
memset(&iop, 0, sizeof(struct inout_port));
|
memset(&iop, 0, sizeof(struct inout_port));
|
||||||
iop.name = "rtc";
|
iop.name = "rtc";
|
||||||
|
Loading…
Reference in New Issue
Block a user