37 |
37 |
#define DPRINTF(...)
|
38 |
38 |
#endif
|
39 |
39 |
|
|
40 |
struct HPETState;
|
|
41 |
typedef struct HPETTimer { /* timers */
|
|
42 |
uint8_t tn; /*timer number*/
|
|
43 |
QEMUTimer *qemu_timer;
|
|
44 |
struct HPETState *state;
|
|
45 |
/* Memory-mapped, software visible timer registers */
|
|
46 |
uint64_t config; /* configuration/cap */
|
|
47 |
uint64_t cmp; /* comparator */
|
|
48 |
uint64_t fsb; /* FSB route, not supported now */
|
|
49 |
/* Hidden register state */
|
|
50 |
uint64_t period; /* Last value written to comparator */
|
|
51 |
uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit
|
|
52 |
* mode. Next pop will be actual timer expiration.
|
|
53 |
*/
|
|
54 |
} HPETTimer;
|
|
55 |
|
|
56 |
typedef struct HPETState {
|
|
57 |
uint64_t hpet_offset;
|
|
58 |
qemu_irq *irqs;
|
|
59 |
HPETTimer timer[HPET_NUM_TIMERS];
|
|
60 |
|
|
61 |
/* Memory-mapped, software visible registers */
|
|
62 |
uint64_t capability; /* capabilities */
|
|
63 |
uint64_t config; /* configuration */
|
|
64 |
uint64_t isr; /* interrupt status reg */
|
|
65 |
uint64_t hpet_counter; /* main counter */
|
|
66 |
} HPETState;
|
|
67 |
|
40 |
68 |
static HPETState *hpet_statep;
|
41 |
69 |
|
42 |
70 |
uint32_t hpet_in_legacy_mode(void)
|
43 |
71 |
{
|
44 |
|
if (hpet_statep)
|
45 |
|
return hpet_statep->config & HPET_CFG_LEGACY;
|
46 |
|
else
|
|
72 |
if (!hpet_statep) {
|
47 |
73 |
return 0;
|
|
74 |
}
|
|
75 |
return hpet_statep->config & HPET_CFG_LEGACY;
|
48 |
76 |
}
|
49 |
77 |
|
50 |
78 |
static uint32_t timer_int_route(struct HPETTimer *timer)
|
51 |
79 |
{
|
52 |
|
uint32_t route;
|
53 |
|
route = (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
|
54 |
|
return route;
|
|
80 |
return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
|
55 |
81 |
}
|
56 |
82 |
|
57 |
83 |
static uint32_t hpet_enabled(void)
|
... | ... | |
108 |
134 |
|
109 |
135 |
static uint64_t hpet_get_ticks(void)
|
110 |
136 |
{
|
111 |
|
uint64_t ticks;
|
112 |
|
ticks = ns_to_ticks(qemu_get_clock(vm_clock) + hpet_statep->hpet_offset);
|
113 |
|
return ticks;
|
|
137 |
return ns_to_ticks(qemu_get_clock(vm_clock) + hpet_statep->hpet_offset);
|
114 |
138 |
}
|
115 |
139 |
|
116 |
140 |
/*
|
... | ... | |
121 |
145 |
|
122 |
146 |
if (t->config & HPET_TN_32BIT) {
|
123 |
147 |
uint32_t diff, cmp;
|
|
148 |
|
124 |
149 |
cmp = (uint32_t)t->cmp;
|
125 |
150 |
diff = cmp - (uint32_t)current;
|
126 |
151 |
diff = (int32_t)diff > 0 ? diff : (uint32_t)0;
|
127 |
152 |
return (uint64_t)diff;
|
128 |
153 |
} else {
|
129 |
154 |
uint64_t diff, cmp;
|
|
155 |
|
130 |
156 |
cmp = t->cmp;
|
131 |
157 |
diff = cmp - current;
|
132 |
158 |
diff = (int64_t)diff > 0 ? diff : (uint64_t)0;
|
... | ... | |
136 |
162 |
|
137 |
163 |
static void update_irq(struct HPETTimer *timer)
|
138 |
164 |
{
|
139 |
|
qemu_irq irq;
|
140 |
165 |
int route;
|
141 |
166 |
|
142 |
167 |
if (timer->tn <= 1 && hpet_in_legacy_mode()) {
|
... | ... | |
144 |
169 |
* timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
|
145 |
170 |
* timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
|
146 |
171 |
*/
|
147 |
|
if (timer->tn == 0) {
|
148 |
|
irq=timer->state->irqs[0];
|
149 |
|
} else
|
150 |
|
irq=timer->state->irqs[8];
|
|
172 |
route = (timer->tn == 0) ? 0 : 8;
|
151 |
173 |
} else {
|
152 |
|
route=timer_int_route(timer);
|
153 |
|
irq=timer->state->irqs[route];
|
|
174 |
route = timer_int_route(timer);
|
154 |
175 |
}
|
155 |
|
if (timer_enabled(timer) && hpet_enabled()) {
|
156 |
|
qemu_irq_pulse(irq);
|
|
176 |
if (!timer_enabled(timer) || !hpet_enabled()) {
|
|
177 |
return;
|
157 |
178 |
}
|
|
179 |
qemu_irq_pulse(timer->state->irqs[route]);
|
158 |
180 |
}
|
159 |
181 |
|
160 |
182 |
static void hpet_pre_save(void *opaque)
|
161 |
183 |
{
|
162 |
184 |
HPETState *s = opaque;
|
|
185 |
|
163 |
186 |
/* save current counter value */
|
164 |
187 |
s->hpet_counter = hpet_get_ticks();
|
165 |
188 |
}
|
... | ... | |
212 |
235 |
*/
|
213 |
236 |
static void hpet_timer(void *opaque)
|
214 |
237 |
{
|
215 |
|
HPETTimer *t = (HPETTimer*)opaque;
|
|
238 |
HPETTimer *t = opaque;
|
216 |
239 |
uint64_t diff;
|
217 |
240 |
|
218 |
241 |
uint64_t period = t->period;
|
... | ... | |
220 |
243 |
|
221 |
244 |
if (timer_is_periodic(t) && period != 0) {
|
222 |
245 |
if (t->config & HPET_TN_32BIT) {
|
223 |
|
while (hpet_time_after(cur_tick, t->cmp))
|
|
246 |
while (hpet_time_after(cur_tick, t->cmp)) {
|
224 |
247 |
t->cmp = (uint32_t)(t->cmp + t->period);
|
225 |
|
} else
|
226 |
|
while (hpet_time_after64(cur_tick, t->cmp))
|
|
248 |
}
|
|
249 |
} else {
|
|
250 |
while (hpet_time_after64(cur_tick, t->cmp)) {
|
227 |
251 |
t->cmp += period;
|
228 |
|
|
|
252 |
}
|
|
253 |
}
|
229 |
254 |
diff = hpet_calculate_diff(t, cur_tick);
|
230 |
|
qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
|
231 |
|
+ (int64_t)ticks_to_ns(diff));
|
|
255 |
qemu_mod_timer(t->qemu_timer,
|
|
256 |
qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff));
|
232 |
257 |
} else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
|
233 |
258 |
if (t->wrap_flag) {
|
234 |
259 |
diff = hpet_calculate_diff(t, cur_tick);
|
235 |
|
qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
|
236 |
|
+ (int64_t)ticks_to_ns(diff));
|
|
260 |
qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) +
|
|
261 |
(int64_t)ticks_to_ns(diff));
|
237 |
262 |
t->wrap_flag = 0;
|
238 |
263 |
}
|
239 |
264 |
}
|
... | ... | |
260 |
285 |
t->wrap_flag = 1;
|
261 |
286 |
}
|
262 |
287 |
}
|
263 |
|
qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
|
264 |
|
+ (int64_t)ticks_to_ns(diff));
|
|
288 |
qemu_mod_timer(t->qemu_timer,
|
|
289 |
qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff));
|
265 |
290 |
}
|
266 |
291 |
|
267 |
292 |
static void hpet_del_timer(HPETTimer *t)
|
... | ... | |
285 |
310 |
|
286 |
311 |
static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)
|
287 |
312 |
{
|
288 |
|
HPETState *s = (HPETState *)opaque;
|
|
313 |
HPETState *s = opaque;
|
289 |
314 |
uint64_t cur_tick, index;
|
290 |
315 |
|
291 |
316 |
DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);
|
... | ... | |
293 |
318 |
/*address range of all TN regs*/
|
294 |
319 |
if (index >= 0x100 && index <= 0x3ff) {
|
295 |
320 |
uint8_t timer_id = (addr - 0x100) / 0x20;
|
|
321 |
HPETTimer *timer = &s->timer[timer_id];
|
|
322 |
|
296 |
323 |
if (timer_id > HPET_NUM_TIMERS - 1) {
|
297 |
324 |
DPRINTF("qemu: timer id out of range\n");
|
298 |
325 |
return 0;
|
299 |
326 |
}
|
300 |
|
HPETTimer *timer = &s->timer[timer_id];
|
301 |
327 |
|
302 |
328 |
switch ((addr - 0x100) % 0x20) {
|
303 |
|
case HPET_TN_CFG:
|
304 |
|
return timer->config;
|
305 |
|
case HPET_TN_CFG + 4: // Interrupt capabilities
|
306 |
|
return timer->config >> 32;
|
307 |
|
case HPET_TN_CMP: // comparator register
|
308 |
|
return timer->cmp;
|
309 |
|
case HPET_TN_CMP + 4:
|
310 |
|
return timer->cmp >> 32;
|
311 |
|
case HPET_TN_ROUTE:
|
312 |
|
return timer->fsb >> 32;
|
313 |
|
default:
|
314 |
|
DPRINTF("qemu: invalid hpet_ram_readl\n");
|
315 |
|
break;
|
|
329 |
case HPET_TN_CFG:
|
|
330 |
return timer->config;
|
|
331 |
case HPET_TN_CFG + 4: // Interrupt capabilities
|
|
332 |
return timer->config >> 32;
|
|
333 |
case HPET_TN_CMP: // comparator register
|
|
334 |
return timer->cmp;
|
|
335 |
case HPET_TN_CMP + 4:
|
|
336 |
return timer->cmp >> 32;
|
|
337 |
case HPET_TN_ROUTE:
|
|
338 |
return timer->fsb >> 32;
|
|
339 |
default:
|
|
340 |
DPRINTF("qemu: invalid hpet_ram_readl\n");
|
|
341 |
break;
|
316 |
342 |
}
|
317 |
343 |
} else {
|
318 |
344 |
switch (index) {
|
319 |
|
case HPET_ID:
|
320 |
|
return s->capability;
|
321 |
|
case HPET_PERIOD:
|
322 |
|
return s->capability >> 32;
|
323 |
|
case HPET_CFG:
|
324 |
|
return s->config;
|
325 |
|
case HPET_CFG + 4:
|
326 |
|
DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");
|
327 |
|
return 0;
|
328 |
|
case HPET_COUNTER:
|
329 |
|
if (hpet_enabled())
|
330 |
|
cur_tick = hpet_get_ticks();
|
331 |
|
else
|
332 |
|
cur_tick = s->hpet_counter;
|
333 |
|
DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick);
|
334 |
|
return cur_tick;
|
335 |
|
case HPET_COUNTER + 4:
|
336 |
|
if (hpet_enabled())
|
337 |
|
cur_tick = hpet_get_ticks();
|
338 |
|
else
|
339 |
|
cur_tick = s->hpet_counter;
|
340 |
|
DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick);
|
341 |
|
return cur_tick >> 32;
|
342 |
|
case HPET_STATUS:
|
343 |
|
return s->isr;
|
344 |
|
default:
|
345 |
|
DPRINTF("qemu: invalid hpet_ram_readl\n");
|
346 |
|
break;
|
|
345 |
case HPET_ID:
|
|
346 |
return s->capability;
|
|
347 |
case HPET_PERIOD:
|
|
348 |
return s->capability >> 32;
|
|
349 |
case HPET_CFG:
|
|
350 |
return s->config;
|
|
351 |
case HPET_CFG + 4:
|
|
352 |
DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");
|
|
353 |
return 0;
|
|
354 |
case HPET_COUNTER:
|
|
355 |
if (hpet_enabled()) {
|
|
356 |
cur_tick = hpet_get_ticks();
|
|
357 |
} else {
|
|
358 |
cur_tick = s->hpet_counter;
|
|
359 |
}
|
|
360 |
DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick);
|
|
361 |
return cur_tick;
|
|
362 |
case HPET_COUNTER + 4:
|
|
363 |
if (hpet_enabled()) {
|
|
364 |
cur_tick = hpet_get_ticks();
|
|
365 |
} else {
|
|
366 |
cur_tick = s->hpet_counter;
|
|
367 |
}
|
|
368 |
DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick);
|
|
369 |
return cur_tick >> 32;
|
|
370 |
case HPET_STATUS:
|
|
371 |
return s->isr;
|
|
372 |
default:
|
|
373 |
DPRINTF("qemu: invalid hpet_ram_readl\n");
|
|
374 |
break;
|
347 |
375 |
}
|
348 |
376 |
}
|
349 |
377 |
return 0;
|
... | ... | |
369 |
397 |
uint32_t value)
|
370 |
398 |
{
|
371 |
399 |
int i;
|
372 |
|
HPETState *s = (HPETState *)opaque;
|
|
400 |
HPETState *s = opaque;
|
373 |
401 |
uint64_t old_val, new_val, val, index;
|
374 |
402 |
|
375 |
403 |
DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value);
|
... | ... | |
380 |
408 |
/*address range of all TN regs*/
|
381 |
409 |
if (index >= 0x100 && index <= 0x3ff) {
|
382 |
410 |
uint8_t timer_id = (addr - 0x100) / 0x20;
|
383 |
|
DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id);
|
384 |
411 |
HPETTimer *timer = &s->timer[timer_id];
|
385 |
412 |
|
|
413 |
DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id);
|
386 |
414 |
if (timer_id > HPET_NUM_TIMERS - 1) {
|
387 |
415 |
DPRINTF("qemu: timer id out of range\n");
|
388 |
416 |
return;
|
389 |
417 |
}
|
390 |
418 |
switch ((addr - 0x100) % 0x20) {
|
391 |
|
case HPET_TN_CFG:
|
392 |
|
DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
|
393 |
|
val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
|
394 |
|
timer->config = (timer->config & 0xffffffff00000000ULL) | val;
|
395 |
|
if (new_val & HPET_TN_32BIT) {
|
396 |
|
timer->cmp = (uint32_t)timer->cmp;
|
397 |
|
timer->period = (uint32_t)timer->period;
|
398 |
|
}
|
399 |
|
if (new_val & HPET_TIMER_TYPE_LEVEL) {
|
400 |
|
printf("qemu: level-triggered hpet not supported\n");
|
401 |
|
exit (-1);
|
402 |
|
}
|
403 |
|
|
404 |
|
break;
|
405 |
|
case HPET_TN_CFG + 4: // Interrupt capabilities
|
406 |
|
DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
|
407 |
|
break;
|
408 |
|
case HPET_TN_CMP: // comparator register
|
409 |
|
DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n");
|
410 |
|
if (timer->config & HPET_TN_32BIT)
|
411 |
|
new_val = (uint32_t)new_val;
|
412 |
|
if (!timer_is_periodic(timer) ||
|
413 |
|
(timer->config & HPET_TN_SETVAL))
|
414 |
|
timer->cmp = (timer->cmp & 0xffffffff00000000ULL)
|
415 |
|
| new_val;
|
416 |
|
if (timer_is_periodic(timer)) {
|
417 |
|
/*
|
418 |
|
* FIXME: Clamp period to reasonable min value?
|
419 |
|
* Clamp period to reasonable max value
|
420 |
|
*/
|
421 |
|
new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
|
422 |
|
timer->period = (timer->period & 0xffffffff00000000ULL)
|
423 |
|
| new_val;
|
|
419 |
case HPET_TN_CFG:
|
|
420 |
DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
|
|
421 |
val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
|
|
422 |
timer->config = (timer->config & 0xffffffff00000000ULL) | val;
|
|
423 |
if (new_val & HPET_TN_32BIT) {
|
|
424 |
timer->cmp = (uint32_t)timer->cmp;
|
|
425 |
timer->period = (uint32_t)timer->period;
|
|
426 |
}
|
|
427 |
if (new_val & HPET_TN_TYPE_LEVEL) {
|
|
428 |
printf("qemu: level-triggered hpet not supported\n");
|
|
429 |
exit (-1);
|
|
430 |
}
|
|
431 |
break;
|
|
432 |
case HPET_TN_CFG + 4: // Interrupt capabilities
|
|
433 |
DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
|
|
434 |
break;
|
|
435 |
case HPET_TN_CMP: // comparator register
|
|
436 |
DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n");
|
|
437 |
if (timer->config & HPET_TN_32BIT) {
|
|
438 |
new_val = (uint32_t)new_val;
|
|
439 |
}
|
|
440 |
if (!timer_is_periodic(timer)
|
|
441 |
|| (timer->config & HPET_TN_SETVAL)) {
|
|
442 |
timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val;
|
|
443 |
}
|
|
444 |
if (timer_is_periodic(timer)) {
|
|
445 |
/*
|
|
446 |
* FIXME: Clamp period to reasonable min value?
|
|
447 |
* Clamp period to reasonable max value
|
|
448 |
*/
|
|
449 |
new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
|
|
450 |
timer->period =
|
|
451 |
(timer->period & 0xffffffff00000000ULL) | new_val;
|
|
452 |
}
|
|
453 |
timer->config &= ~HPET_TN_SETVAL;
|
|
454 |
if (hpet_enabled()) {
|
|
455 |
hpet_set_timer(timer);
|
|
456 |
}
|
|
457 |
break;
|
|
458 |
case HPET_TN_CMP + 4: // comparator register high order
|
|
459 |
DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
|
|
460 |
if (!timer_is_periodic(timer)
|
|
461 |
|| (timer->config & HPET_TN_SETVAL)) {
|
|
462 |
timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32;
|
|
463 |
} else {
|
|
464 |
/*
|
|
465 |
* FIXME: Clamp period to reasonable min value?
|
|
466 |
* Clamp period to reasonable max value
|
|
467 |
*/
|
|
468 |
new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
|
|
469 |
timer->period =
|
|
470 |
(timer->period & 0xffffffffULL) | new_val << 32;
|
424 |
471 |
}
|
425 |
472 |
timer->config &= ~HPET_TN_SETVAL;
|
426 |
|
if (hpet_enabled())
|
|
473 |
if (hpet_enabled()) {
|
427 |
474 |
hpet_set_timer(timer);
|
428 |
|
break;
|
429 |
|
case HPET_TN_CMP + 4: // comparator register high order
|
430 |
|
DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
|
431 |
|
if (!timer_is_periodic(timer) ||
|
432 |
|
(timer->config & HPET_TN_SETVAL))
|
433 |
|
timer->cmp = (timer->cmp & 0xffffffffULL)
|
434 |
|
| new_val << 32;
|
435 |
|
else {
|
436 |
|
/*
|
437 |
|
* FIXME: Clamp period to reasonable min value?
|
438 |
|
* Clamp period to reasonable max value
|
439 |
|
*/
|
440 |
|
new_val &= (timer->config
|
441 |
|
& HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
|
442 |
|
timer->period = (timer->period & 0xffffffffULL)
|
443 |
|
| new_val << 32;
|
444 |
475 |
}
|
445 |
|
timer->config &= ~HPET_TN_SETVAL;
|
446 |
|
if (hpet_enabled())
|
447 |
|
hpet_set_timer(timer);
|
448 |
|
break;
|
449 |
|
case HPET_TN_ROUTE + 4:
|
450 |
|
DPRINTF("qemu: hpet_ram_writel HPET_TN_ROUTE + 4\n");
|
451 |
|
break;
|
452 |
|
default:
|
453 |
|
DPRINTF("qemu: invalid hpet_ram_writel\n");
|
454 |
476 |
break;
|
|
477 |
case HPET_TN_ROUTE + 4:
|
|
478 |
DPRINTF("qemu: hpet_ram_writel HPET_TN_ROUTE + 4\n");
|
|
479 |
break;
|
|
480 |
default:
|
|
481 |
DPRINTF("qemu: invalid hpet_ram_writel\n");
|
|
482 |
break;
|
455 |
483 |
}
|
456 |
484 |
return;
|
457 |
485 |
} else {
|
458 |
486 |
switch (index) {
|
459 |
|
case HPET_ID:
|
460 |
|
return;
|
461 |
|
case HPET_CFG:
|
462 |
|
val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
|
463 |
|
s->config = (s->config & 0xffffffff00000000ULL) | val;
|
464 |
|
if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
465 |
|
/* Enable main counter and interrupt generation. */
|
466 |
|
s->hpet_offset = ticks_to_ns(s->hpet_counter)
|
467 |
|
- qemu_get_clock(vm_clock);
|
468 |
|
for (i = 0; i < HPET_NUM_TIMERS; i++)
|
469 |
|
if ((&s->timer[i])->cmp != ~0ULL)
|
470 |
|
hpet_set_timer(&s->timer[i]);
|
471 |
|
}
|
472 |
|
else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
473 |
|
/* Halt main counter and disable interrupt generation. */
|
474 |
|
s->hpet_counter = hpet_get_ticks();
|
475 |
|
for (i = 0; i < HPET_NUM_TIMERS; i++)
|
476 |
|
hpet_del_timer(&s->timer[i]);
|
|
487 |
case HPET_ID:
|
|
488 |
return;
|
|
489 |
case HPET_CFG:
|
|
490 |
val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
|
|
491 |
s->config = (s->config & 0xffffffff00000000ULL) | val;
|
|
492 |
if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
|
493 |
/* Enable main counter and interrupt generation. */
|
|
494 |
s->hpet_offset =
|
|
495 |
ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
|
|
496 |
for (i = 0; i < HPET_NUM_TIMERS; i++) {
|
|
497 |
if ((&s->timer[i])->cmp != ~0ULL) {
|
|
498 |
hpet_set_timer(&s->timer[i]);
|
|
499 |
}
|
477 |
500 |
}
|
478 |
|
/* i8254 and RTC are disabled when HPET is in legacy mode */
|
479 |
|
if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
|
480 |
|
hpet_pit_disable();
|
481 |
|
} else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
|
482 |
|
hpet_pit_enable();
|
|
501 |
} else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
|
502 |
/* Halt main counter and disable interrupt generation. */
|
|
503 |
s->hpet_counter = hpet_get_ticks();
|
|
504 |
for (i = 0; i < HPET_NUM_TIMERS; i++) {
|
|
505 |
hpet_del_timer(&s->timer[i]);
|
483 |
506 |
}
|
484 |
|
break;
|
485 |
|
case HPET_CFG + 4:
|
486 |
|
DPRINTF("qemu: invalid HPET_CFG+4 write \n");
|
487 |
|
break;
|
488 |
|
case HPET_STATUS:
|
489 |
|
/* FIXME: need to handle level-triggered interrupts */
|
490 |
|
break;
|
491 |
|
case HPET_COUNTER:
|
492 |
|
if (hpet_enabled())
|
493 |
|
printf("qemu: Writing counter while HPET enabled!\n");
|
494 |
|
s->hpet_counter = (s->hpet_counter & 0xffffffff00000000ULL)
|
495 |
|
| value;
|
496 |
|
DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
|
497 |
|
value, s->hpet_counter);
|
498 |
|
break;
|
499 |
|
case HPET_COUNTER + 4:
|
500 |
|
if (hpet_enabled())
|
501 |
|
printf("qemu: Writing counter while HPET enabled!\n");
|
502 |
|
s->hpet_counter = (s->hpet_counter & 0xffffffffULL)
|
503 |
|
| (((uint64_t)value) << 32);
|
504 |
|
DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
|
505 |
|
value, s->hpet_counter);
|
506 |
|
break;
|
507 |
|
default:
|
508 |
|
DPRINTF("qemu: invalid hpet_ram_writel\n");
|
509 |
|
break;
|
|
507 |
}
|
|
508 |
/* i8254 and RTC are disabled when HPET is in legacy mode */
|
|
509 |
if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
|
|
510 |
hpet_pit_disable();
|
|
511 |
} else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
|
|
512 |
hpet_pit_enable();
|
|
513 |
}
|
|
514 |
break;
|
|
515 |
case HPET_CFG + 4:
|
|
516 |
DPRINTF("qemu: invalid HPET_CFG+4 write \n");
|
|
517 |
break;
|
|
518 |
case HPET_STATUS:
|
|
519 |
/* FIXME: need to handle level-triggered interrupts */
|
|
520 |
break;
|
|
521 |
case HPET_COUNTER:
|
|
522 |
if (hpet_enabled()) {
|
|
523 |
printf("qemu: Writing counter while HPET enabled!\n");
|
|
524 |
}
|
|
525 |
s->hpet_counter =
|
|
526 |
(s->hpet_counter & 0xffffffff00000000ULL) | value;
|
|
527 |
DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
|
|
528 |
value, s->hpet_counter);
|
|
529 |
break;
|
|
530 |
case HPET_COUNTER + 4:
|
|
531 |
if (hpet_enabled()) {
|
|
532 |
printf("qemu: Writing counter while HPET enabled!\n");
|
|
533 |
}
|
|
534 |
s->hpet_counter =
|
|
535 |
(s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
|
|
536 |
DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
|
|
537 |
value, s->hpet_counter);
|
|
538 |
break;
|
|
539 |
default:
|
|
540 |
DPRINTF("qemu: invalid hpet_ram_writel\n");
|
|
541 |
break;
|
510 |
542 |
}
|
511 |
543 |
}
|
512 |
544 |
}
|
... | ... | |
533 |
565 |
hpet_ram_writel,
|
534 |
566 |
};
|
535 |
567 |
|
536 |
|
static void hpet_reset(void *opaque) {
|
|
568 |
static void hpet_reset(void *opaque)
|
|
569 |
{
|
537 |
570 |
HPETState *s = opaque;
|
538 |
571 |
int i;
|
539 |
572 |
static int count = 0;
|
540 |
573 |
|
541 |
|
for (i=0; i<HPET_NUM_TIMERS; i++) {
|
|
574 |
for (i = 0; i < HPET_NUM_TIMERS; i++) {
|
542 |
575 |
HPETTimer *timer = &s->timer[i];
|
|
576 |
|
543 |
577 |
hpet_del_timer(timer);
|
544 |
578 |
timer->tn = i;
|
545 |
579 |
timer->cmp = ~0ULL;
|
... | ... | |
557 |
591 |
s->capability = 0x8086a201ULL;
|
558 |
592 |
s->capability |= ((HPET_CLK_PERIOD) << 32);
|
559 |
593 |
s->config = 0ULL;
|
560 |
|
if (count > 0)
|
|
594 |
if (count > 0) {
|
561 |
595 |
/* we don't enable pit when hpet_reset is first called (by hpet_init)
|
562 |
596 |
* because hpet is taking over for pit here. On subsequent invocations,
|
563 |
597 |
* hpet_reset is called due to system reset. At this point control must
|
564 |
598 |
* be returned to pit until SW reenables hpet.
|
565 |
599 |
*/
|
566 |
600 |
hpet_pit_enable();
|
|
601 |
}
|
567 |
602 |
count = 1;
|
568 |
603 |
}
|
569 |
604 |
|
570 |
605 |
|
571 |
|
void hpet_init(qemu_irq *irq) {
|
|
606 |
void hpet_init(qemu_irq *irq)
|
|
607 |
{
|
572 |
608 |
int i, iomemtype;
|
|
609 |
HPETTimer *timer;
|
573 |
610 |
HPETState *s;
|
574 |
611 |
|
575 |
612 |
DPRINTF ("hpet_init\n");
|
... | ... | |
577 |
614 |
s = qemu_mallocz(sizeof(HPETState));
|
578 |
615 |
hpet_statep = s;
|
579 |
616 |
s->irqs = irq;
|
580 |
|
for (i=0; i<HPET_NUM_TIMERS; i++) {
|
581 |
|
HPETTimer *timer = &s->timer[i];
|
|
617 |
for (i = 0; i < HPET_NUM_TIMERS; i++) {
|
|
618 |
timer = &s->timer[i];
|
582 |
619 |
timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer);
|
583 |
620 |
}
|
584 |
621 |
vmstate_register(-1, &vmstate_hpet, s);
|