From 16b29ae1807b024bd5052301550f5d47dae958a2 Mon Sep 17 00:00:00 2001 From: aliguori Date: Wed, 17 Dec 2008 23:28:44 +0000 Subject: [PATCH] Add HPET emulation to qemu (Beth Kon) This patch adds HPET emulation. It can be disabled with -disable-hpet. An hpet provides a more finely granular clocksource than otherwise available on PC. This means that latency-dependent applications (e.g. multimedia) will generally be smoother when using the HPET. Signed-off-by: Beth Kon Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6081 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/apic.c | 7 + hw/hpet.c | 588 ++++++++++++++++++++++++++++++++ hw/hpet_emul.h | 85 +++++ hw/i8254.c | 21 ++ hw/mc146818rtc.c | 29 +- hw/pc.c | 4 + hw/pc.h | 3 + monitor.c | 7 + pc-bios/bios-pq/0005_hpet.patch | 190 +++++++++++ pc-bios/bios-pq/series | 1 + pc-bios/bios.bin | Bin 131072 -> 131072 bytes vl.c | 7 + 13 files changed, 938 insertions(+), 6 deletions(-) create mode 100644 hw/hpet.c create mode 100644 hw/hpet_emul.h create mode 100644 pc-bios/bios-pq/0005_hpet.patch diff --git a/Makefile.target b/Makefile.target index e14309c05b..6886aadea0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -635,7 +635,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o -OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o +OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o # virtio support OBJS+= virtio.o virtio-blk.o virtio-balloon.o virtio-net.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE diff --git a/hw/apic.c b/hw/apic.c index a2915f8121..f6950ca4d4 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -945,6 +945,13 @@ void ioapic_set_irq(void *opaque, int vector, int level) { IOAPICState *s = opaque; + /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps + * to GSI 2. GSI maps to ioapic 1-1. This is not + * the cleanest way of doing it but it should work. */ + + if (vector == 0) + vector = 2; + if (vector >= 0 && vector < IOAPIC_NUM_PINS) { uint32_t mask = 1 << vector; uint64_t entry = s->ioredtbl[vector]; diff --git a/hw/hpet.c b/hw/hpet.c new file mode 100644 index 0000000000..0dc05620c0 --- /dev/null +++ b/hw/hpet.c @@ -0,0 +1,588 @@ +/* + * High Precisition Event Timer emulation + * + * Copyright (c) 2007 Alexander Graf + * Copyright (c) 2008 IBM Corporation + * + * Authors: Beth Kon + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ***************************************************************** + * + * This driver attempts to emulate an HPET device in software. + */ + +#include "hw.h" +#include "console.h" +#include "qemu-timer.h" +#include "hpet_emul.h" + +extern void hpet_pit_disable(void); +extern void hpet_pit_enable(void); + +//#define HPET_DEBUG +#ifdef HPET_DEBUG +#define dprintf printf +#else +#define dprintf(...) +#endif + +static HPETState *hpet_statep; + +uint32_t hpet_in_legacy_mode(void) +{ + if (hpet_statep) + return hpet_statep->config & HPET_CFG_LEGACY; + else + return 0; +} + +static uint32_t timer_int_route(struct HPETTimer *timer) +{ + uint32_t route; + route = (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT; + return route; +} + +static uint32_t hpet_enabled(void) +{ + return hpet_statep->config & HPET_CFG_ENABLE; +} + +static uint32_t timer_is_periodic(HPETTimer *t) +{ + return t->config & HPET_TN_PERIODIC; +} + +static uint32_t timer_enabled(HPETTimer *t) +{ + return t->config & HPET_TN_ENABLE; +} + +static uint32_t hpet_time_after(uint64_t a, uint64_t b) +{ + return ((int32_t)(b) - (int32_t)(a) < 0); +} + +static uint32_t hpet_time_after64(uint64_t a, uint64_t b) +{ + return ((int64_t)(b) - (int64_t)(a) < 0); +} + +static uint64_t ticks_to_ns(uint64_t value) +{ + return (muldiv64(value, HPET_CLK_PERIOD, FS_PER_NS)); +} + +static uint64_t ns_to_ticks(uint64_t value) +{ + return (muldiv64(value, FS_PER_NS, HPET_CLK_PERIOD)); +} + +static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask) +{ + new &= mask; + new |= old & ~mask; + return new; +} + +static int activating_bit(uint64_t old, uint64_t new, uint64_t mask) +{ + return (!(old & mask) && (new & mask)); +} + +static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask) +{ + return ((old & mask) && !(new & mask)); +} + +static uint64_t hpet_get_ticks(void) +{ + uint64_t ticks; + ticks = ns_to_ticks(qemu_get_clock(vm_clock) + hpet_statep->hpet_offset); + return ticks; +} + +/* + * calculate diff between comparator value and current ticks + */ +static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current) +{ + + if (t->config & HPET_TN_32BIT) { + uint32_t diff, cmp; + cmp = (uint32_t)t->cmp; + diff = cmp - (uint32_t)current; + diff = (int32_t)diff > 0 ? diff : (uint32_t)0; + return (uint64_t)diff; + } else { + uint64_t diff, cmp; + cmp = t->cmp; + diff = cmp - current; + diff = (int64_t)diff > 0 ? diff : (uint64_t)0; + return diff; + } +} + +static void update_irq(struct HPETTimer *timer) +{ + qemu_irq irq; + int route; + + if (timer->tn <= 1 && hpet_in_legacy_mode()) { + /* if LegacyReplacementRoute bit is set, HPET specification requires + * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC, + * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. + */ + if (timer->tn == 0) { + irq=timer->state->irqs[0]; + } else + irq=timer->state->irqs[8]; + } else { + route=timer_int_route(timer); + irq=timer->state->irqs[route]; + } + if (timer_enabled(timer) && hpet_enabled()) { + qemu_irq_pulse(irq); + } +} + +static void hpet_save(QEMUFile *f, void *opaque) +{ + HPETState *s = opaque; + int i; + qemu_put_be64s(f, &s->config); + qemu_put_be64s(f, &s->isr); + /* save current counter value */ + s->hpet_counter = hpet_get_ticks(); + qemu_put_be64s(f, &s->hpet_counter); + + for (i = 0; i < HPET_NUM_TIMERS; i++) { + qemu_put_8s(f, &s->timer[i].tn); + qemu_put_be64s(f, &s->timer[i].config); + qemu_put_be64s(f, &s->timer[i].cmp); + qemu_put_be64s(f, &s->timer[i].fsb); + qemu_put_be64s(f, &s->timer[i].period); + qemu_put_8s(f, &s->timer[i].wrap_flag); + if (s->timer[i].qemu_timer) { + qemu_put_timer(f, s->timer[i].qemu_timer); + } + } +} + +static int hpet_load(QEMUFile *f, void *opaque, int version_id) +{ + HPETState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be64s(f, &s->config); + qemu_get_be64s(f, &s->isr); + qemu_get_be64s(f, &s->hpet_counter); + /* Recalculate the offset between the main counter and guest time */ + s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock); + + for (i = 0; i < HPET_NUM_TIMERS; i++) { + qemu_get_8s(f, &s->timer[i].tn); + qemu_get_be64s(f, &s->timer[i].config); + qemu_get_be64s(f, &s->timer[i].cmp); + qemu_get_be64s(f, &s->timer[i].fsb); + qemu_get_be64s(f, &s->timer[i].period); + qemu_get_8s(f, &s->timer[i].wrap_flag); + if (s->timer[i].qemu_timer) { + qemu_get_timer(f, s->timer[i].qemu_timer); + } + } + return 0; +} + +/* + * timer expiration callback + */ +static void hpet_timer(void *opaque) +{ + HPETTimer *t = (HPETTimer*)opaque; + uint64_t diff; + + uint64_t period = t->period; + uint64_t cur_tick = hpet_get_ticks(); + + if (timer_is_periodic(t) && period != 0) { + if (t->config & HPET_TN_32BIT) { + while (hpet_time_after(cur_tick, t->cmp)) + t->cmp = (uint32_t)(t->cmp + t->period); + } else + while (hpet_time_after64(cur_tick, t->cmp)) + t->cmp += period; + + diff = hpet_calculate_diff(t, cur_tick); + qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) + + (int64_t)ticks_to_ns(diff)); + } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { + if (t->wrap_flag) { + diff = hpet_calculate_diff(t, cur_tick); + qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) + + (int64_t)ticks_to_ns(diff)); + t->wrap_flag = 0; + } + } + update_irq(t); +} + +static void hpet_set_timer(HPETTimer *t) +{ + uint64_t diff; + uint32_t wrap_diff; /* how many ticks until we wrap? */ + uint64_t cur_tick = hpet_get_ticks(); + + /* whenever new timer is being set up, make sure wrap_flag is 0 */ + t->wrap_flag = 0; + diff = hpet_calculate_diff(t, cur_tick); + + /* hpet spec says in one-shot 32-bit mode, generate an interrupt when + * counter wraps in addition to an interrupt with comparator match. + */ + if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { + wrap_diff = 0xffffffff - (uint32_t)cur_tick; + if (wrap_diff < (uint32_t)diff) { + diff = wrap_diff; + t->wrap_flag = 1; + } + } + qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) + + (int64_t)ticks_to_ns(diff)); +} + +static void hpet_del_timer(HPETTimer *t) +{ + qemu_del_timer(t->qemu_timer); +} + +#ifdef HPET_DEBUG +static uint32_t hpet_ram_readb(void *opaque, target_phys_addr_t addr) +{ + printf("qemu: hpet_read b at %" PRIx64 "\n", addr); + return 0; +} + +static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr) +{ + printf("qemu: hpet_read w at %" PRIx64 "\n", addr); + return 0; +} +#endif + +static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr) +{ + HPETState *s = (HPETState *)opaque; + uint64_t cur_tick, index; + + dprintf("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr); + index = addr; + /*address range of all TN regs*/ + if (index >= 0x100 && index <= 0x3ff) { + uint8_t timer_id = (addr - 0x100) / 0x20; + if (timer_id > HPET_NUM_TIMERS - 1) { + printf("qemu: timer id out of range\n"); + return 0; + } + HPETTimer *timer = &s->timer[timer_id]; + + switch ((addr - 0x100) % 0x20) { + case HPET_TN_CFG: + return timer->config; + case HPET_TN_CFG + 4: // Interrupt capabilities + return timer->config >> 32; + case HPET_TN_CMP: // comparator register + return timer->cmp; + case HPET_TN_CMP + 4: + return timer->cmp >> 32; + case HPET_TN_ROUTE: + return timer->fsb >> 32; + default: + dprintf("qemu: invalid hpet_ram_readl\n"); + break; + } + } else { + switch (index) { + case HPET_ID: + return s->capability; + case HPET_PERIOD: + return s->capability >> 32; + case HPET_CFG: + return s->config; + case HPET_CFG + 4: + dprintf("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n"); + return 0; + case HPET_COUNTER: + if (hpet_enabled()) + cur_tick = hpet_get_ticks(); + else + cur_tick = s->hpet_counter; + dprintf("qemu: reading counter = %" PRIx64 "\n", cur_tick); + return cur_tick; + case HPET_COUNTER + 4: + if (hpet_enabled()) + cur_tick = hpet_get_ticks(); + else + cur_tick = s->hpet_counter; + dprintf("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick); + return cur_tick >> 32; + case HPET_STATUS: + return s->isr; + default: + dprintf("qemu: invalid hpet_ram_readl\n"); + break; + } + } + return 0; +} + +#ifdef HPET_DEBUG +static void hpet_ram_writeb(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + printf("qemu: invalid hpet_write b at %" PRIx64 " = %#x\n", + addr, value); +} + +static void hpet_ram_writew(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + printf("qemu: invalid hpet_write w at %" PRIx64 " = %#x\n", + addr, value); +} +#endif + +static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + int i; + HPETState *s = (HPETState *)opaque; + uint64_t old_val, new_val, index; + + dprintf("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value); + index = addr; + old_val = hpet_ram_readl(opaque, addr); + new_val = value; + + /*address range of all TN regs*/ + if (index >= 0x100 && index <= 0x3ff) { + uint8_t timer_id = (addr - 0x100) / 0x20; + dprintf("qemu: hpet_ram_writel timer_id = %#x \n", timer_id); + HPETTimer *timer = &s->timer[timer_id]; + + switch ((addr - 0x100) % 0x20) { + case HPET_TN_CFG: + dprintf("qemu: hpet_ram_writel HPET_TN_CFG\n"); + timer->config = hpet_fixup_reg(new_val, old_val, 0x3e4e); + if (new_val & HPET_TN_32BIT) { + timer->cmp = (uint32_t)timer->cmp; + timer->period = (uint32_t)timer->period; + } + if (new_val & HPET_TIMER_TYPE_LEVEL) { + printf("qemu: level-triggered hpet not supported\n"); + exit (-1); + } + + break; + case HPET_TN_CFG + 4: // Interrupt capabilities + dprintf("qemu: invalid HPET_TN_CFG+4 write\n"); + break; + case HPET_TN_CMP: // comparator register + dprintf("qemu: hpet_ram_writel HPET_TN_CMP \n"); + if (timer->config & HPET_TN_32BIT) + new_val = (uint32_t)new_val; + if (!timer_is_periodic(timer) || + (timer->config & HPET_TN_SETVAL)) + timer->cmp = (timer->cmp & 0xffffffff00000000ULL) + | new_val; + else { + /* + * FIXME: Clamp period to reasonable min value? + * Clamp period to reasonable max value + */ + new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; + timer->period = (timer->period & 0xffffffff00000000ULL) + | new_val; + } + timer->config &= ~HPET_TN_SETVAL; + if (hpet_enabled()) + hpet_set_timer(timer); + break; + case HPET_TN_CMP + 4: // comparator register high order + dprintf("qemu: hpet_ram_writel HPET_TN_CMP + 4\n"); + if (!timer_is_periodic(timer) || + (timer->config & HPET_TN_SETVAL)) + timer->cmp = (timer->cmp & 0xffffffffULL) + | new_val << 32; + else { + /* + * FIXME: Clamp period to reasonable min value? + * Clamp period to reasonable max value + */ + new_val &= (timer->config + & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; + timer->period = (timer->period & 0xffffffffULL) + | new_val << 32; + } + timer->config &= ~HPET_TN_SETVAL; + if (hpet_enabled()) + hpet_set_timer(timer); + break; + case HPET_TN_ROUTE + 4: + dprintf("qemu: hpet_ram_writel HPET_TN_ROUTE + 4\n"); + break; + default: + dprintf("qemu: invalid hpet_ram_writel\n"); + break; + } + return; + } else { + switch (index) { + case HPET_ID: + return; + case HPET_CFG: + s->config = hpet_fixup_reg(new_val, old_val, 0x3); + if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { + /* Enable main counter and interrupt generation. */ + s->hpet_offset = ticks_to_ns(s->hpet_counter) + - qemu_get_clock(vm_clock); + for (i = 0; i < HPET_NUM_TIMERS; i++) + if ((&s->timer[i])->cmp != ~0ULL) + hpet_set_timer(&s->timer[i]); + } + else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { + /* Halt main counter and disable interrupt generation. */ + s->hpet_counter = hpet_get_ticks(); + for (i = 0; i < HPET_NUM_TIMERS; i++) + hpet_del_timer(&s->timer[i]); + } + /* i8254 and RTC are disabled when HPET is in legacy mode */ + if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { + hpet_pit_disable(); + } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { + hpet_pit_enable(); + } + break; + case HPET_CFG + 4: + dprintf("qemu: invalid HPET_CFG+4 write \n"); + break; + case HPET_STATUS: + /* FIXME: need to handle level-triggered interrupts */ + break; + case HPET_COUNTER: + if (hpet_enabled()) + printf("qemu: Writing counter while HPET enabled!\n"); + s->hpet_counter = (s->hpet_counter & 0xffffffff00000000ULL) + | value; + dprintf("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n", + value, s->hpet_counter); + break; + case HPET_COUNTER + 4: + if (hpet_enabled()) + printf("qemu: Writing counter while HPET enabled!\n"); + s->hpet_counter = (s->hpet_counter & 0xffffffffULL) + | (((uint64_t)value) << 32); + dprintf("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n", + value, s->hpet_counter); + break; + default: + dprintf("qemu: invalid hpet_ram_writel\n"); + break; + } + } +} + +static CPUReadMemoryFunc *hpet_ram_read[] = { +#ifdef HPET_DEBUG + hpet_ram_readb, + hpet_ram_readw, +#else + NULL, + NULL, +#endif + hpet_ram_readl, +}; + +static CPUWriteMemoryFunc *hpet_ram_write[] = { +#ifdef HPET_DEBUG + hpet_ram_writeb, + hpet_ram_writew, +#else + NULL, + NULL, +#endif + hpet_ram_writel, +}; + +static void hpet_reset(void *opaque) { + HPETState *s = opaque; + int i; + static int count = 0; + + for (i=0; itimer[i]; + hpet_del_timer(timer); + timer->tn = i; + timer->cmp = ~0ULL; + timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; + /* advertise availability of irqs 5,10,11 */ + timer->config |= 0x00000c20ULL << 32; + timer->state = s; + timer->period = 0ULL; + timer->wrap_flag = 0; + } + + s->hpet_counter = 0ULL; + s->hpet_offset = 0ULL; + /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */ + s->capability = 0x8086a201ULL; + s->capability |= ((HPET_CLK_PERIOD) << 32); + if (count > 0) + /* we don't enable pit when hpet_reset is first called (by hpet_init) + * because hpet is taking over for pit here. On subsequent invocations, + * hpet_reset is called due to system reset. At this point control must + * be returned to pit until SW reenables hpet. + */ + hpet_pit_enable(); + count = 1; +} + + +void hpet_init(qemu_irq *irq) { + int i, iomemtype; + HPETState *s; + + dprintf ("hpet_init\n"); + + s = qemu_mallocz(sizeof(HPETState)); + hpet_statep = s; + s->irqs = irq; + for (i=0; itimer[i]; + timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer); + } + hpet_reset(s); + register_savevm("hpet", -1, 1, hpet_save, hpet_load, s); + qemu_register_reset(hpet_reset, s); + /* HPET Area */ + iomemtype = cpu_register_io_memory(0, hpet_ram_read, + hpet_ram_write, s); + cpu_register_physical_memory(HPET_BASE, 0x400, iomemtype); +} diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h new file mode 100644 index 0000000000..93a277e263 --- /dev/null +++ b/hw/hpet_emul.h @@ -0,0 +1,85 @@ +/* + * QEMU Emulated HPET support + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Beth Kon + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#ifndef QEMU_HPET_EMUL_H +#define QEMU_HPET_EMUL_H + +#define HPET_BASE 0xfed00000 +#define HPET_CLK_PERIOD 10000000ULL /* 10000000 femtoseconds == 10ns*/ + +#define FS_PER_NS 1000000 +#define HPET_NUM_TIMERS 3 +#define HPET_TIMER_TYPE_LEVEL 1 +#define HPET_TIMER_TYPE_EDGE 0 +#define HPET_TIMER_DELIVERY_APIC 0 +#define HPET_TIMER_DELIVERY_FSB 1 +#define HPET_TIMER_CAP_FSB_INT_DEL (1 << 15) +#define HPET_TIMER_CAP_PER_INT (1 << 4) + +#define HPET_CFG_ENABLE 0x001 +#define HPET_CFG_LEGACY 0x002 + +#define HPET_ID 0x000 +#define HPET_PERIOD 0x004 +#define HPET_CFG 0x010 +#define HPET_STATUS 0x020 +#define HPET_COUNTER 0x0f0 +#define HPET_TN_CFG 0x000 +#define HPET_TN_CMP 0x008 +#define HPET_TN_ROUTE 0x010 + + +#define HPET_TN_ENABLE 0x004 +#define HPET_TN_PERIODIC 0x008 +#define HPET_TN_PERIODIC_CAP 0x010 +#define HPET_TN_SIZE_CAP 0x020 +#define HPET_TN_SETVAL 0x040 +#define HPET_TN_32BIT 0x100 +#define HPET_TN_INT_ROUTE_MASK 0x3e00 +#define HPET_TN_INT_ROUTE_SHIFT 9 +#define HPET_TN_INT_ROUTE_CAP_SHIFT 32 +#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U + +struct HPETState; +typedef struct HPETTimer { /* timers */ + uint8_t tn; /*timer number*/ + QEMUTimer *qemu_timer; + struct HPETState *state; + /* Memory-mapped, software visible timer registers */ + uint64_t config; /* configuration/cap */ + uint64_t cmp; /* comparator */ + uint64_t fsb; /* FSB route, not supported now */ + /* Hidden register state */ + uint64_t period; /* Last value written to comparator */ + uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit + * mode. Next pop will be actual timer expiration. + */ +} HPETTimer; + +typedef struct HPETState { + uint64_t hpet_offset; + qemu_irq *irqs; + HPETTimer timer[HPET_NUM_TIMERS]; + + /* Memory-mapped, software visible registers */ + uint64_t capability; /* capabilities */ + uint64_t config; /* configuration */ + uint64_t isr; /* interrupt status reg */ + uint64_t hpet_counter; /* main counter */ +} HPETState; + +#if defined TARGET_I386 || defined TARGET_X86_64 +extern uint32_t hpet_in_legacy_mode(void); +extern void hpet_init(qemu_irq *irq); +#endif + +#endif diff --git a/hw/i8254.c b/hw/i8254.c index 4813b0374c..16257872d9 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -463,6 +463,27 @@ static void pit_reset(void *opaque) } } +/* When HPET is operating in legacy mode, i8254 timer0 is disabled */ +void hpet_pit_disable(void) { + PITChannelState *s; + s = &pit_state.channels[0]; + qemu_del_timer(s->irq_timer); +} + +/* When HPET is reset or leaving legacy mode, it must reenable i8254 + * timer 0 + */ + +void hpet_pit_enable(void) +{ + PITState *pit = &pit_state; + PITChannelState *s; + s = &pit->channels[0]; + s->mode = 3; + s->gate = 1; + pit_load_count(s, 0); +} + PITState *pit_init(int base, qemu_irq irq) { PITState *pit = &pit_state; diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index ac41a947b8..d25b52b4d3 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -26,6 +26,7 @@ #include "sysemu.h" #include "pc.h" #include "isa.h" +#include "hpet_emul.h" //#define DEBUG_CMOS @@ -69,6 +70,18 @@ struct RTCState { QEMUTimer *second_timer2; }; +static void rtc_irq_raise(qemu_irq irq) { + /* When HPET is operating in legacy mode, RTC interrupts are disabled + * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy + * mode is established while interrupt is raised. We want it to + * be lowered in any case + */ +#if defined TARGET_I386 || defined TARGET_X86_64 + if (!hpet_in_legacy_mode()) +#endif + qemu_irq_raise(irq); +} + static void rtc_set_time(RTCState *s); static void rtc_copy_date(RTCState *s); @@ -78,8 +91,14 @@ static void rtc_timer_update(RTCState *s, int64_t current_time) int64_t cur_clock, next_irq_clock; period_code = s->cmos_data[RTC_REG_A] & 0x0f; - if (period_code != 0 && - (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { +#if defined TARGET_I386 || defined TARGET_X86_64 + /* disable periodic timer if hpet is in legacy mode, since interrupts are + * disabled anyway. + */ + if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) { +#else + if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { +#endif if (period_code <= 2) period_code += 7; /* period in 32 Khz cycles */ @@ -100,7 +119,7 @@ static void rtc_periodic_timer(void *opaque) rtc_timer_update(s, s->next_periodic_time); s->cmos_data[RTC_REG_C] |= 0xc0; - qemu_irq_raise(s->irq); + rtc_irq_raise(s->irq); } static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) @@ -319,14 +338,14 @@ static void rtc_update_second2(void *opaque) s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) { s->cmos_data[RTC_REG_C] |= 0xa0; - qemu_irq_raise(s->irq); + rtc_irq_raise(s->irq); } } /* update ended interrupt */ if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { s->cmos_data[RTC_REG_C] |= 0x90; - qemu_irq_raise(s->irq); + rtc_irq_raise(s->irq); } /* clear update in progress bit */ diff --git a/hw/pc.c b/hw/pc.c index fe03704288..64c08a4342 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -35,6 +35,7 @@ #include "fw_cfg.h" #include "virtio-blk.h" #include "virtio-balloon.h" +#include "hpet_emul.h" /* output Bochs bios info messages */ //#define DEBUG_BIOS @@ -977,6 +978,9 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, } pit = pit_init(0x40, i8259[0]); pcspk_init(pit); + if (!no_hpet) { + hpet_init(i8259); + } if (pci_enabled) { pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); } diff --git a/hw/pc.h b/hw/pc.h index b0b8970496..8433084221 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -97,6 +97,9 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); void acpi_bios_init(void); +/* hpet.c */ +extern int no_hpet; + /* pcspk.c */ void pcspk_init(PITState *); int pcspk_audio_init(AudioState *, qemu_irq *pic); diff --git a/monitor.c b/monitor.c index 0d55433172..042d2b0bd7 100644 --- a/monitor.c +++ b/monitor.c @@ -252,6 +252,11 @@ static void do_info_name(void) term_printf("%s\n", qemu_name); } +static void do_info_hpet(void) +{ + term_printf("HPET is %s by QEMU\n", (no_hpet) ? "disabled" : "enabled"); +} + static void do_info_uuid(void) { term_printf(UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], @@ -1531,6 +1536,8 @@ static const term_cmd_t info_cmds[] = { "", "show virtual to physical memory mappings", }, { "mem", "", mem_info, "", "show the active virtual memory mappings", }, + { "hpet", "", do_info_hpet, + "", "show state of HPET", }, #endif { "jit", "", do_info_jit, "", "show dynamic compiler info", }, diff --git a/pc-bios/bios-pq/0005_hpet.patch b/pc-bios/bios-pq/0005_hpet.patch new file mode 100644 index 0000000000..9347cb501e --- /dev/null +++ b/pc-bios/bios-pq/0005_hpet.patch @@ -0,0 +1,190 @@ +BOCHS BIOS changes to support HPET in QEMU. + +Signed-off-by Beth Kon + +Index: bochs-2.3.7/bios/acpi-dsdt.dsl +=================================================================== +--- bochs-2.3.7.orig/bios/acpi-dsdt.dsl 2008-10-15 12:39:14.000000000 -0500 ++++ bochs-2.3.7/bios/acpi-dsdt.dsl 2008-10-28 07:58:40.000000000 -0500 +@@ -159,6 +159,26 @@ + Return (MEMP) + } + } ++#ifdef BX_QEMU ++ Device(HPET) { ++ Name(_HID, EISAID("PNP0103")) ++ Name(_UID, 0) ++ Method (_STA, 0, NotSerialized) { ++ Return(0x0F) ++ } ++ Name(_CRS, ResourceTemplate() { ++ DWordMemory( ++ ResourceConsumer, PosDecode, MinFixed, MaxFixed, ++ NonCacheable, ReadWrite, ++ 0x00000000, ++ 0xFED00000, ++ 0xFED003FF, ++ 0x00000000, ++ 0x00000400 /* 1K memory: FED00000 - FED003FF */ ++ ) ++ }) ++ } ++#endif + } + + Scope(\_SB.PCI0) { +Index: bochs-2.3.7/bios/rombios32.c +=================================================================== +--- bochs-2.3.7.orig/bios/rombios32.c 2008-10-15 12:39:36.000000000 -0500 ++++ bochs-2.3.7/bios/rombios32.c 2008-11-12 14:41:41.000000000 -0600 +@@ -1087,7 +1087,11 @@ + struct rsdt_descriptor_rev1 + { + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ ++#ifdef BX_QEMU ++ uint32_t table_offset_entry [4]; /* Array of pointers to other */ ++#else + uint32_t table_offset_entry [3]; /* Array of pointers to other */ ++#endif + /* ACPI tables */ + }; + +@@ -1227,6 +1231,32 @@ + #endif + }; + ++#ifdef BX_QEMU ++/* ++ * * ACPI 2.0 Generic Address Space definition. ++ * */ ++struct acpi_20_generic_address { ++ uint8_t address_space_id; ++ uint8_t register_bit_width; ++ uint8_t register_bit_offset; ++ uint8_t reserved; ++ uint64_t address; ++}; ++ ++/* ++ * * HPET Description Table ++ * */ ++struct acpi_20_hpet { ++ ACPI_TABLE_HEADER_DEF /* ACPI common table header */ ++ uint32_t timer_block_id; ++ struct acpi_20_generic_address addr; ++ uint8_t hpet_number; ++ uint16_t min_tick; ++ uint8_t page_protect; ++}; ++#define ACPI_HPET_ADDRESS 0xFED00000UL ++#endif ++ + struct madt_io_apic + { + APIC_HEADER_DEF +@@ -1237,6 +1267,17 @@ + * lines start */ + }; + ++#ifdef BX_QEMU ++struct madt_int_override ++{ ++ APIC_HEADER_DEF ++ uint8_t bus; /* Identifies ISA Bus */ ++ uint8_t source; /* Bus-relative interrupt source */ ++ uint32_t gsi; /* GSI that source will signal */ ++ uint16_t flags; /* MPS INTI flags */ ++}; ++#endif ++ + #include "acpi-dsdt.hex" + + static inline uint16_t cpu_to_le16(uint16_t x) +@@ -1342,6 +1383,10 @@ + struct facs_descriptor_rev1 *facs; + struct multiple_apic_table *madt; + uint8_t *dsdt, *ssdt; ++#ifdef BX_QEMU ++ struct acpi_20_hpet *hpet; ++ uint32_t hpet_addr; ++#endif + uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr; + uint32_t acpi_tables_size, madt_addr, madt_size; + int i; +@@ -1384,10 +1429,21 @@ + madt_addr = addr; + madt_size = sizeof(*madt) + + sizeof(struct madt_processor_apic) * smp_cpus + ++#ifdef BX_QEMU ++ sizeof(struct madt_io_apic) + sizeof(struct madt_int_override); ++#else + sizeof(struct madt_io_apic); ++#endif + madt = (void *)(addr); + addr += madt_size; + ++#ifdef BX_QEMU ++ addr = (addr + 7) & ~7; ++ hpet_addr = addr; ++ hpet = (void *)(addr); ++ addr += sizeof(*hpet); ++#endif ++ + acpi_tables_size = addr - base_addr; + + BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n", +@@ -1410,6 +1466,9 @@ + rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr); + rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr); + rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr); ++#ifdef BX_QEMU ++ rsdt->table_offset_entry[3] = cpu_to_le32(hpet_addr); ++#endif + acpi_build_table_header((struct acpi_table_header *)rsdt, + "RSDT", sizeof(*rsdt), 1); + +@@ -1448,6 +1507,9 @@ + { + struct madt_processor_apic *apic; + struct madt_io_apic *io_apic; ++#ifdef BX_QEMU ++ struct madt_int_override *int_override; ++#endif + + memset(madt, 0, madt_size); + madt->local_apic_address = cpu_to_le32(0xfee00000); +@@ -1467,10 +1529,34 @@ + io_apic->io_apic_id = smp_cpus; + io_apic->address = cpu_to_le32(0xfec00000); + io_apic->interrupt = cpu_to_le32(0); ++#ifdef BX_QEMU ++ io_apic++; ++ ++ int_override = (void *)io_apic; ++ int_override->type = APIC_XRUPT_OVERRIDE; ++ int_override->length = sizeof(*int_override); ++ int_override->bus = cpu_to_le32(0); ++ int_override->source = cpu_to_le32(0); ++ int_override->gsi = cpu_to_le32(2); ++ int_override->flags = cpu_to_le32(0); ++#endif + + acpi_build_table_header((struct acpi_table_header *)madt, + "APIC", madt_size, 1); + } ++ ++#ifdef BX_QEMU ++ /* HPET */ ++ memset(hpet, 0, sizeof(*hpet)); ++ /* Note timer_block_id value must be kept in sync with value advertised by ++ * emulated hpet ++ */ ++ hpet->timer_block_id = cpu_to_le32(0x8086a201); ++ hpet->addr.address = cpu_to_le32(ACPI_HPET_ADDRESS); ++ acpi_build_table_header((struct acpi_table_header *)hpet, ++ "HPET", sizeof(*hpet), 1); ++#endif ++ + } + + /* SMBIOS entry point -- must be written to a 16-bit aligned address diff --git a/pc-bios/bios-pq/series b/pc-bios/bios-pq/series index 96a4f9d8dc..beff2c6d44 100644 --- a/pc-bios/bios-pq/series +++ b/pc-bios/bios-pq/series @@ -2,3 +2,4 @@ 0002_e820-high-mem.patch 0003_smp-startup-poll.patch 0004_no-stack-protector.patch +0005_hpet.patch diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 4aa218b28ccc6e4202026fb4872882361ddb67b1..c401d25ca9cffaba97bbcfd0a4c5df2629550d31 100644 GIT binary patch delta 22023 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 diff --git a/vl.c b/vl.c index 0a021515ab..66dd975f84 100644 --- a/vl.c +++ b/vl.c @@ -224,6 +224,7 @@ int usb_enabled = 0; int smp_cpus = 1; const char *vnc_display; int acpi_enabled = 1; +int no_hpet = 0; int fd_bootchk = 1; int no_reboot = 0; int no_shutdown = 0; @@ -3956,6 +3957,7 @@ static void help(int exitcode) #endif #ifdef TARGET_I386 "-no-acpi disable ACPI\n" + "-no-hpet disable HPET\n" #endif #ifdef CONFIG_CURSES "-curses use a curses/ncurses interface instead of SDL\n" @@ -4067,6 +4069,7 @@ enum { QEMU_OPTION_smp, QEMU_OPTION_vnc, QEMU_OPTION_no_acpi, + QEMU_OPTION_no_hpet, QEMU_OPTION_curses, QEMU_OPTION_no_reboot, QEMU_OPTION_no_shutdown, @@ -4180,6 +4183,7 @@ static const QEMUOption qemu_options[] = { /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, { "no-acpi", 0, QEMU_OPTION_no_acpi }, + { "no-hpet", 0, QEMU_OPTION_no_hpet }, { "no-reboot", 0, QEMU_OPTION_no_reboot }, { "no-shutdown", 0, QEMU_OPTION_no_shutdown }, { "show-cursor", 0, QEMU_OPTION_show_cursor }, @@ -5017,6 +5021,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_no_acpi: acpi_enabled = 0; break; + case QEMU_OPTION_no_hpet: + no_hpet = 1; + break; case QEMU_OPTION_no_reboot: no_reboot = 1; break;