40 |
40 |
|
41 |
41 |
//#define DEBUG_IRQ
|
42 |
42 |
//#define DEBUG_EBUS
|
|
43 |
//#define DEBUG_TIMER
|
43 |
44 |
|
44 |
45 |
#ifdef DEBUG_IRQ
|
45 |
46 |
#define CPUIRQ_DPRINTF(fmt, ...) \
|
... | ... | |
55 |
56 |
#define EBUS_DPRINTF(fmt, ...)
|
56 |
57 |
#endif
|
57 |
58 |
|
|
59 |
#ifdef DEBUG_TIMER
|
|
60 |
#define TIMER_DPRINTF(fmt, ...) \
|
|
61 |
do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
|
|
62 |
#else
|
|
63 |
#define TIMER_DPRINTF(fmt, ...)
|
|
64 |
#endif
|
|
65 |
|
58 |
66 |
#define KERNEL_LOAD_ADDR 0x00404000
|
59 |
67 |
#define CMDLINE_ADDR 0x003ff000
|
60 |
68 |
#define INITRD_LOAD_ADDR 0x00300000
|
... | ... | |
282 |
290 |
}
|
283 |
291 |
}
|
284 |
292 |
|
|
293 |
static void cpu_kick_irq(CPUState *env)
|
|
294 |
{
|
|
295 |
env->halted = 0;
|
|
296 |
cpu_check_irqs(env);
|
|
297 |
}
|
|
298 |
|
285 |
299 |
static void cpu_set_irq(void *opaque, int irq, int level)
|
286 |
300 |
{
|
287 |
301 |
CPUState *env = opaque;
|
... | ... | |
303 |
317 |
uint64_t prom_addr;
|
304 |
318 |
} ResetData;
|
305 |
319 |
|
|
320 |
void cpu_put_timer(QEMUFile *f, CPUTimer *s)
|
|
321 |
{
|
|
322 |
qemu_put_be32s(f, &s->frequency);
|
|
323 |
qemu_put_be32s(f, &s->disabled);
|
|
324 |
qemu_put_be64s(f, &s->disabled_mask);
|
|
325 |
qemu_put_sbe64s(f, &s->clock_offset);
|
|
326 |
|
|
327 |
qemu_put_timer(f, s->qtimer);
|
|
328 |
}
|
|
329 |
|
|
330 |
void cpu_get_timer(QEMUFile *f, CPUTimer *s)
|
|
331 |
{
|
|
332 |
qemu_get_be32s(f, &s->frequency);
|
|
333 |
qemu_get_be32s(f, &s->disabled);
|
|
334 |
qemu_get_be64s(f, &s->disabled_mask);
|
|
335 |
qemu_get_sbe64s(f, &s->clock_offset);
|
|
336 |
|
|
337 |
qemu_get_timer(f, s->qtimer);
|
|
338 |
}
|
|
339 |
|
|
340 |
static CPUTimer* cpu_timer_create(const char* name, CPUState *env,
|
|
341 |
QEMUBHFunc *cb, uint32_t frequency,
|
|
342 |
uint64_t disabled_mask)
|
|
343 |
{
|
|
344 |
CPUTimer *timer = qemu_mallocz(sizeof (CPUTimer));
|
|
345 |
|
|
346 |
timer->name = name;
|
|
347 |
timer->frequency = frequency;
|
|
348 |
timer->disabled_mask = disabled_mask;
|
|
349 |
|
|
350 |
timer->disabled = 1;
|
|
351 |
timer->clock_offset = qemu_get_clock(vm_clock);
|
|
352 |
|
|
353 |
timer->qtimer = qemu_new_timer(vm_clock, cb, env);
|
|
354 |
|
|
355 |
return timer;
|
|
356 |
}
|
|
357 |
|
|
358 |
static void cpu_timer_reset(CPUTimer *timer)
|
|
359 |
{
|
|
360 |
timer->disabled = 1;
|
|
361 |
timer->clock_offset = qemu_get_clock(vm_clock);
|
|
362 |
|
|
363 |
qemu_del_timer(timer->qtimer);
|
|
364 |
}
|
|
365 |
|
306 |
366 |
static void main_cpu_reset(void *opaque)
|
307 |
367 |
{
|
308 |
368 |
ResetData *s = (ResetData *)opaque;
|
... | ... | |
310 |
370 |
static unsigned int nr_resets;
|
311 |
371 |
|
312 |
372 |
cpu_reset(env);
|
313 |
|
env->tick_cmpr = TICK_INT_DIS | 0;
|
314 |
|
ptimer_set_limit(env->tick, TICK_MAX, 1);
|
315 |
|
ptimer_run(env->tick, 1);
|
316 |
|
env->stick_cmpr = TICK_INT_DIS | 0;
|
317 |
|
ptimer_set_limit(env->stick, TICK_MAX, 1);
|
318 |
|
ptimer_run(env->stick, 1);
|
319 |
|
env->hstick_cmpr = TICK_INT_DIS | 0;
|
320 |
|
ptimer_set_limit(env->hstick, TICK_MAX, 1);
|
321 |
|
ptimer_run(env->hstick, 1);
|
|
373 |
|
|
374 |
cpu_timer_reset(env->tick);
|
|
375 |
cpu_timer_reset(env->stick);
|
|
376 |
cpu_timer_reset(env->hstick);
|
|
377 |
|
322 |
378 |
env->gregs[1] = 0; // Memory start
|
323 |
379 |
env->gregs[2] = ram_size; // Memory size
|
324 |
380 |
env->gregs[3] = 0; // Machine description XXX
|
... | ... | |
335 |
391 |
{
|
336 |
392 |
CPUState *env = opaque;
|
337 |
393 |
|
338 |
|
if (!(env->tick_cmpr & TICK_INT_DIS)) {
|
339 |
|
env->softint |= SOFTINT_TIMER;
|
340 |
|
cpu_interrupt(env, CPU_INTERRUPT_TIMER);
|
|
394 |
CPUTimer* timer = env->tick;
|
|
395 |
|
|
396 |
if (timer->disabled) {
|
|
397 |
CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
|
|
398 |
return;
|
|
399 |
} else {
|
|
400 |
CPUIRQ_DPRINTF("tick: fire\n");
|
341 |
401 |
}
|
|
402 |
|
|
403 |
env->softint |= SOFTINT_TIMER;
|
|
404 |
cpu_kick_irq(env);
|
342 |
405 |
}
|
343 |
406 |
|
344 |
407 |
static void stick_irq(void *opaque)
|
345 |
408 |
{
|
346 |
409 |
CPUState *env = opaque;
|
347 |
410 |
|
348 |
|
if (!(env->stick_cmpr & TICK_INT_DIS)) {
|
349 |
|
env->softint |= SOFTINT_STIMER;
|
350 |
|
cpu_interrupt(env, CPU_INTERRUPT_TIMER);
|
|
411 |
CPUTimer* timer = env->stick;
|
|
412 |
|
|
413 |
if (timer->disabled) {
|
|
414 |
CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
|
|
415 |
return;
|
|
416 |
} else {
|
|
417 |
CPUIRQ_DPRINTF("stick: fire\n");
|
351 |
418 |
}
|
|
419 |
|
|
420 |
env->softint |= SOFTINT_STIMER;
|
|
421 |
cpu_kick_irq(env);
|
352 |
422 |
}
|
353 |
423 |
|
354 |
424 |
static void hstick_irq(void *opaque)
|
355 |
425 |
{
|
356 |
426 |
CPUState *env = opaque;
|
357 |
427 |
|
358 |
|
if (!(env->hstick_cmpr & TICK_INT_DIS)) {
|
359 |
|
cpu_interrupt(env, CPU_INTERRUPT_TIMER);
|
|
428 |
CPUTimer* timer = env->hstick;
|
|
429 |
|
|
430 |
if (timer->disabled) {
|
|
431 |
CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
|
|
432 |
return;
|
|
433 |
} else {
|
|
434 |
CPUIRQ_DPRINTF("hstick: fire\n");
|
360 |
435 |
}
|
|
436 |
|
|
437 |
env->softint |= SOFTINT_STIMER;
|
|
438 |
cpu_kick_irq(env);
|
|
439 |
}
|
|
440 |
|
|
441 |
static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
|
|
442 |
{
|
|
443 |
return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency);
|
|
444 |
}
|
|
445 |
|
|
446 |
static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
|
|
447 |
{
|
|
448 |
return muldiv64(timer_ticks, frequency, get_ticks_per_sec());
|
361 |
449 |
}
|
362 |
450 |
|
363 |
|
void cpu_tick_set_count(void *opaque, uint64_t count)
|
|
451 |
void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
|
364 |
452 |
{
|
365 |
|
ptimer_set_count(opaque, -count);
|
|
453 |
uint64_t real_count = count & ~timer->disabled_mask;
|
|
454 |
uint64_t disabled_bit = count & timer->disabled_mask;
|
|
455 |
|
|
456 |
int64_t vm_clock_offset = qemu_get_clock(vm_clock) -
|
|
457 |
cpu_to_timer_ticks(real_count, timer->frequency);
|
|
458 |
|
|
459 |
TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n",
|
|
460 |
timer->name, real_count,
|
|
461 |
timer->disabled?"disabled":"enabled", timer);
|
|
462 |
|
|
463 |
timer->disabled = disabled_bit ? 1 : 0;
|
|
464 |
timer->clock_offset = vm_clock_offset;
|
366 |
465 |
}
|
367 |
466 |
|
368 |
|
uint64_t cpu_tick_get_count(void *opaque)
|
|
467 |
uint64_t cpu_tick_get_count(CPUTimer *timer)
|
369 |
468 |
{
|
370 |
|
return -ptimer_get_count(opaque);
|
|
469 |
uint64_t real_count = timer_to_cpu_ticks(
|
|
470 |
qemu_get_clock(vm_clock) - timer->clock_offset,
|
|
471 |
timer->frequency);
|
|
472 |
|
|
473 |
TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n",
|
|
474 |
timer->name, real_count,
|
|
475 |
timer->disabled?"disabled":"enabled", timer);
|
|
476 |
|
|
477 |
if (timer->disabled)
|
|
478 |
real_count |= timer->disabled_mask;
|
|
479 |
|
|
480 |
return real_count;
|
371 |
481 |
}
|
372 |
482 |
|
373 |
|
void cpu_tick_set_limit(void *opaque, uint64_t limit)
|
|
483 |
void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
|
374 |
484 |
{
|
375 |
|
ptimer_set_limit(opaque, -limit, 0);
|
|
485 |
int64_t now = qemu_get_clock(vm_clock);
|
|
486 |
|
|
487 |
uint64_t real_limit = limit & ~timer->disabled_mask;
|
|
488 |
timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
|
|
489 |
|
|
490 |
int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
|
|
491 |
timer->clock_offset;
|
|
492 |
|
|
493 |
if (expires < now) {
|
|
494 |
expires = now + 1;
|
|
495 |
}
|
|
496 |
|
|
497 |
TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
|
|
498 |
"called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
|
|
499 |
timer->name, real_limit,
|
|
500 |
timer->disabled?"disabled":"enabled",
|
|
501 |
timer, limit,
|
|
502 |
timer_to_cpu_ticks(now - timer->clock_offset,
|
|
503 |
timer->frequency),
|
|
504 |
timer_to_cpu_ticks(expires - now, timer->frequency));
|
|
505 |
|
|
506 |
if (!real_limit) {
|
|
507 |
TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
|
|
508 |
timer->name);
|
|
509 |
qemu_del_timer(timer->qtimer);
|
|
510 |
} else if (timer->disabled) {
|
|
511 |
qemu_del_timer(timer->qtimer);
|
|
512 |
} else {
|
|
513 |
qemu_mod_timer(timer->qtimer, expires);
|
|
514 |
}
|
376 |
515 |
}
|
377 |
516 |
|
378 |
517 |
static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
|
... | ... | |
559 |
698 |
static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
|
560 |
699 |
{
|
561 |
700 |
CPUState *env;
|
562 |
|
QEMUBH *bh;
|
563 |
701 |
ResetData *reset_info;
|
564 |
702 |
|
|
703 |
uint32_t tick_frequency = 100*1000000;
|
|
704 |
uint32_t stick_frequency = 100*1000000;
|
|
705 |
uint32_t hstick_frequency = 100*1000000;
|
|
706 |
|
565 |
707 |
if (!cpu_model)
|
566 |
708 |
cpu_model = hwdef->default_cpu_model;
|
567 |
709 |
env = cpu_init(cpu_model);
|
... | ... | |
569 |
711 |
fprintf(stderr, "Unable to find Sparc CPU definition\n");
|
570 |
712 |
exit(1);
|
571 |
713 |
}
|
572 |
|
bh = qemu_bh_new(tick_irq, env);
|
573 |
|
env->tick = ptimer_init(bh);
|
574 |
|
ptimer_set_period(env->tick, 1ULL);
|
575 |
714 |
|
576 |
|
bh = qemu_bh_new(stick_irq, env);
|
577 |
|
env->stick = ptimer_init(bh);
|
578 |
|
ptimer_set_period(env->stick, 1ULL);
|
|
715 |
env->tick = cpu_timer_create("tick", env, tick_irq,
|
|
716 |
tick_frequency, TICK_NPT_MASK);
|
|
717 |
|
|
718 |
env->stick = cpu_timer_create("stick", env, stick_irq,
|
|
719 |
stick_frequency, TICK_INT_DIS);
|
579 |
720 |
|
580 |
|
bh = qemu_bh_new(hstick_irq, env);
|
581 |
|
env->hstick = ptimer_init(bh);
|
582 |
|
ptimer_set_period(env->hstick, 1ULL);
|
|
721 |
env->hstick = cpu_timer_create("hstick", env, hstick_irq,
|
|
722 |
hstick_frequency, TICK_INT_DIS);
|
583 |
723 |
|
584 |
724 |
reset_info = qemu_mallocz(sizeof(ResetData));
|
585 |
725 |
reset_info->env = env;
|