Skip to content

Commit 8fdea84

Browse files
jsun26intelwenlingz
authored andcommitted
DM: use acrn_timer api to emulate wdt
In the current implementation sigev_notify is configured as SIGEV_THREAD. When wdt expires an async thread is created and the registered timer callback is called in the context of this thread, then the watchdog interrupt emulation would require the thread to assert intr on this pci dev. There would be a race condition that when the wdt pci device is freed in pci device deinit and then a timer expires. In this case the wdt expired thread will access a freed buffer which would cause problem such as heap corruption and segment fault. In this patch we replace timer API with acrn_timer which is based on timerfd/epoll mechanism to avoid the race condition. Tracked-On: #1489 Signed-off-by: Victor Sun <victor.sun@intel.com> Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com> Reviewed-by: Minggui Cao <minggui.cao@intel.com> Acked-by: Yin Fengwei <fengwei.yin@intel.com>
1 parent 6ffa1aa commit 8fdea84

File tree

1 file changed

+27
-70
lines changed

1 file changed

+27
-70
lines changed

devicemodel/hw/pci/wdt_i6300esb.c

Lines changed: 27 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@
1313
#include <stdio.h>
1414
#include <stdlib.h>
1515
#include <string.h>
16-
#include <signal.h>
17-
#include <time.h>
1816
#include <assert.h>
1917
#include <stdbool.h>
2018

2119
#include "vmmapi.h"
2220
#include "mevent.h"
2321
#include "pci_core.h"
22+
#include "timer.h"
2423

2524
#define WDT_REG_BAR_SIZE 0x10
2625

@@ -55,8 +54,6 @@
5554
#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
5655
#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
5756

58-
#define WDT_TIMER_SIG 0x55AA
59-
6057
/* the default 20-bit preload value */
6158
#define DEFAULT_MAX_TIMER_VAL 0x000FFFFF
6259

@@ -77,13 +74,13 @@ do { fprintf(dbg_file, format, args); fflush(dbg_file); } while (0)
7774
#endif
7875

7976
struct info_wdt {
77+
struct acrn_timer timer;
78+
8079
bool reboot_enabled;/* "reboot" on wdt out */
8180

8281
bool locked; /* If true, enabled field cannot be changed. */
8382
bool wdt_enabled; /* If true, watchdog is enabled. */
84-
85-
bool timer_created;
86-
timer_t wdt_timerid;
83+
bool wdt_armed;
8784

8885
uint32_t timer1_val;
8986
uint32_t timer2_val;
@@ -107,10 +104,10 @@ static void start_wdt_timer(void);
107104
* action to guest OS
108105
*/
109106
static void
110-
wdt_expired_thread(union sigval v)
107+
wdt_expired_handler(void *arg)
111108
{
112-
DPRINTF("wdt timer out! id=0x%x, stage=%d, reboot=%d\n",
113-
v.sival_int, wdt_state.stage, wdt_state.reboot_enabled);
109+
DPRINTF("wdt timer out! stage=%d, reboot=%d\n",
110+
wdt_state.stage, wdt_state.reboot_enabled);
114111

115112
if (wdt_state.stage == 1) {
116113
wdt_state.stage = 2;
@@ -136,51 +133,20 @@ stop_wdt_timer(void)
136133
{
137134
struct itimerspec timer_val;
138135

139-
DPRINTF("%s: timer_created=%d\n", __func__, wdt_state.timer_created);
136+
DPRINTF("%s: wdt_armed=%d\n", __func__, wdt_state.wdt_armed);
140137

141-
if (!wdt_state.timer_created)
138+
if (!wdt_state.wdt_armed)
142139
return;
143140

144141
memset(&timer_val, 0, sizeof(struct itimerspec));
145-
timer_settime(wdt_state.wdt_timerid, 0, &timer_val, NULL);
146-
}
147-
148-
static void
149-
delete_wdt_timer(void)
150-
{
151-
if (!wdt_state.timer_created)
152-
return;
153-
154-
DPRINTF("%s: timer %ld deleted\n", __func__,
155-
(uint64_t)wdt_state.wdt_timerid);
156-
157-
timer_delete(wdt_state.wdt_timerid);
158-
wdt_state.timer_created = false;
159-
}
160-
161-
static void
162-
reset_wdt_timer(int seconds)
163-
{
164-
struct itimerspec timer_val;
165-
166-
DPRINTF("%s: time=%d\n", __func__, seconds);
167-
memset(&timer_val, 0, sizeof(struct itimerspec));
168-
timer_settime(wdt_state.wdt_timerid, 0, &timer_val, NULL);
169-
170-
timer_val.it_value.tv_sec = seconds;
171-
if (timer_settime(wdt_state.wdt_timerid, 0, &timer_val, NULL) == -1) {
172-
perror("timer_settime failed.\n");
173-
timer_delete(wdt_state.wdt_timerid);
174-
wdt_state.timer_created = 0;
175-
exit(-1);
176-
}
142+
acrn_timer_settime(&wdt_state.timer, &timer_val);
143+
wdt_state.wdt_armed = false;
177144
}
178145

179146
static void
180147
start_wdt_timer(void)
181148
{
182149
int seconds;
183-
struct sigevent sig_evt;
184150
struct itimerspec timer_val;
185151

186152
if (!wdt_state.wdt_enabled)
@@ -191,34 +157,19 @@ start_wdt_timer(void)
191157
else
192158
seconds = TIMER_TO_SECONDS(wdt_state.timer2_val);
193159

194-
DPRINTF("%s: created=%d, time=%d\n", __func__,
195-
wdt_state.timer_created, seconds);
196-
memset(&sig_evt, 0, sizeof(struct sigevent));
197-
if (wdt_state.timer_created) {
198-
reset_wdt_timer(seconds);
199-
return;
200-
}
201-
202-
sig_evt.sigev_value.sival_int = WDT_TIMER_SIG;
203-
sig_evt.sigev_notify = SIGEV_THREAD;
204-
sig_evt.sigev_notify_function = wdt_expired_thread;
205-
206-
if (timer_create(CLOCK_REALTIME, &sig_evt,
207-
&wdt_state.wdt_timerid) == -1) {
208-
perror("timer_create failed.\n");
209-
exit(-1);
210-
}
160+
DPRINTF("%s: armed=%d, time=%d\n", __func__,
161+
wdt_state.wdt_armed, seconds);
211162

212163
memset(&timer_val, 0, sizeof(struct itimerspec));
213164
timer_val.it_value.tv_sec = seconds;
214165

215-
if (timer_settime(wdt_state.wdt_timerid, 0, &timer_val, NULL) == -1) {
216-
perror("timer_settime failed.\n");
217-
timer_delete(wdt_state.wdt_timerid);
218-
exit(-1);
166+
if (acrn_timer_settime(&wdt_state.timer, &timer_val) == -1) {
167+
perror("WDT timerfd_settime failed.\n");
168+
wdt_state.wdt_armed = false;
169+
return;
219170
}
220171

221-
wdt_state.timer_created = true;
172+
wdt_state.wdt_armed = true;
222173
}
223174

224175
static int
@@ -341,14 +292,19 @@ pci_wdt_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
341292
{
342293
/*the wdt just has one inistance */
343294
if (wdt_state.reboot_enabled && wdt_state.timer1_val) {
344-
perror("wdt can't be created twice, please check!");
295+
perror("wdt can't be initialized twice, please check!");
345296
return -1;
346297
}
347298

348299
/* init wdt state info */
300+
wdt_state.timer.clockid = CLOCK_MONOTONIC;
301+
if (acrn_timer_init(&wdt_state.timer, wdt_expired_handler, dev) != 0) {
302+
return -1;
303+
}
304+
349305
wdt_state.reboot_enabled = true;
350306
wdt_state.locked = false;
351-
wdt_state.timer_created = false;
307+
wdt_state.wdt_armed = false;
352308
wdt_state.wdt_enabled = false;
353309

354310
wdt_state.stage = 1;
@@ -377,7 +333,8 @@ pci_wdt_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
377333
static void
378334
pci_wdt_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
379335
{
380-
delete_wdt_timer();
336+
acrn_timer_deinit(&wdt_state.timer);
337+
381338
memset(&wdt_state, 0, sizeof(wdt_state));
382339
}
383340

0 commit comments

Comments
 (0)