* [Qemu-devel] [PATCH 2/9] HPET device
@ 2008-01-08 15:22 Alexander Graf
0 siblings, 0 replies; only message in thread
From: Alexander Graf @ 2008-01-08 15:22 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 300 bytes --]
This patch adds an HPET emulator device. Normally the HPET is not used
by Mac OS X, but required to exist. This is mostly a dummy
implementation to satisfy Mac OS X and I am not sure if it is safe to
use. As it is only activated on the IntelMac target, I do not expect any
problems with that though.
[-- Attachment #2: qemu-hpet.patch --]
[-- Type: text/x-patch, Size: 10326 bytes --]
Index: qemu-snapshot-2008-01-08_05/Makefile.target
===================================================================
--- qemu-snapshot-2008-01-08_05.orig/Makefile.target
+++ qemu-snapshot-2008-01-08_05/Makefile.target
@@ -441,7 +441,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
-VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o smbios.o
+VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o smbios.o hpet.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
Index: qemu-snapshot-2008-01-08_05/hw/hpet.c
===================================================================
--- /dev/null
+++ qemu-snapshot-2008-01-08_05/hw/hpet.c
@@ -0,0 +1,294 @@
+/*
+ * High Precisition Event Timer emulation
+ *
+ * Copyright (c) 2007 Alexander Graf
+ *
+ * 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. It is by no
+ * means complete and is prone to break on certain conditions.
+ *
+ */
+#include "hw.h"
+#include "console.h"
+#include "qemu-timer.h"
+
+
+#define HPET_BASE 0xfed00000
+
+#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)
+
+qemu_irq hpet_irq;
+
+struct HPETState;
+typedef struct HPETTimer {
+ QEMUTimer *timer;
+ struct HPETState *state;
+ uint8_t type;
+ uint8_t active;
+ uint8_t delivery;
+ uint8_t apic_port;
+ uint8_t periodic;
+ uint8_t enabled;
+ uint32_t comparator; // if(hpet_counter == comparator) IRQ();
+} HPETTimer;
+
+typedef struct HPETState {
+ QEMUTimer *periodic_timer;
+ uint64_t hpet_counter;
+ int64_t next_periodic_time;
+ HPETTimer timer[HPET_NUM_TIMERS];
+} HPETState;
+
+static void hpet_timer(void *opaque)
+{
+ HPETTimer *s = (HPETTimer*)opaque;
+ printf("hpet i!\n");
+ if(s->periodic) {
+ printf("periodic hpet!\n");
+ qemu_mod_timer(s->timer, qemu_get_clock(vm_clock) + ((s->comparator) * (ticks_per_sec * 99) / 100));
+ }
+ // XXX use s->apic_port
+ qemu_irq_raise(hpet_irq);
+}
+
+static void hpet_periodic_timer(void *opaque)
+{
+ HPETState *s = opaque;
+
+ s->hpet_counter += ticks_per_sec;
+ s->next_periodic_time += ticks_per_sec;
+ // rtc_timer_update(s, s->next_periodic_time);
+ // s->cmos_data[RTC_REG_C] |= 0xc0;
+ qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
+ printf("hpet p!\n");
+ qemu_irq_raise(0);
+}
+
+static void hpet_check(HPETTimer *s)
+{
+ if(s->enabled) {
+ if(s->periodic)
+ qemu_mod_timer(s->timer, qemu_get_clock(vm_clock) + s->comparator * (ticks_per_sec * 99) / 100);
+ else
+ qemu_mod_timer(s->timer, qemu_get_clock(vm_clock) + ((s->comparator - s->state->hpet_counter) * (ticks_per_sec * 99) / 100));
+ }
+}
+
+static uint32_t hpet_ram_readb(void *opaque, target_phys_addr_t addr)
+{
+#ifdef HPET_DEBUG
+ printf("qemu: hpet_read b at %#lx\n", addr);
+#endif
+ return 10;
+}
+
+static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr)
+{
+#ifdef HPET_DEBUG
+ printf("qemu: hpet_read w at %#lx\n", addr);
+#endif
+ return 10;
+}
+
+static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)
+{
+ HPETState *s = (HPETState *)opaque;
+#ifdef HPET_DEBUG
+ printf("qemu: hpet_read l at %#lx\n", addr);
+#endif
+ switch(addr - HPET_BASE) {
+ case 0x00:
+ return 0x8086a201;
+ case 0x04:
+ return 0x0429b17f;
+ case 0x10:
+ case 0x14:
+ return 0;
+ case 0xf0:
+ return s->hpet_counter;
+ case 0xf4:
+ return 0;
+ case 0x20:
+ {
+ uint32_t retval = 0;
+ int i;
+ for(i=0; i<HPET_NUM_TIMERS; i++) {
+ if(s->timer[i].type == HPET_TIMER_TYPE_LEVEL)
+ retval |= s->timer[i].active << i;
+ }
+ return retval;
+ }
+ default:
+ {
+ uint8_t timer_id = (addr - HPET_BASE - 0x100) / 0x20;
+ switch((addr - HPET_BASE - 0x100) % 0x20) {
+ case 0x0:
+ return ((s->timer[timer_id].delivery == HPET_TIMER_DELIVERY_FSB) << 14)
+ | (s->timer[timer_id].apic_port << 9)
+ | HPET_TIMER_CAP_PER_INT
+ | (s->timer[timer_id].periodic << 3)
+ | (s->timer[timer_id].enabled << 2)
+ | (s->timer[timer_id].type << 1);
+ case 0x4: // Interrupt capabilities
+ return 0x00ff;
+ case 0x8: // comparator register
+ return s->timer[timer_id].comparator;
+ case 0xc:
+ return 0x0;
+ }
+ }
+ }
+
+#ifdef HPET_DEBUG
+ printf("qemu: invalid hpet_read l at %#x\n", addr);
+#endif
+ return 10;
+}
+
+static void hpet_ram_writeb(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+#ifdef HPET_DEBUG
+ printf("qemu: invalid hpet_write b at %#x = %#x\n", addr, value);
+#endif
+}
+
+static void hpet_ram_writew(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+#ifdef HPET_DEBUG
+ printf("qemu: invalid hpet_write w at %#x = %#x\n", addr, value);
+#endif
+}
+
+static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ HPETState *s = (HPETState *)opaque;
+#ifdef HPET_DEBUG
+ printf("qemu: hpet_write l at %#x = %#x\n", addr, value);
+#endif
+ switch(addr - HPET_BASE) {
+ case 0x00:
+ return;
+ case 0x10:
+ case 0x14:
+ if(value == 0) {
+ // disable hpet interrupts
+ } else if(value == 1) {
+ // enable all hpet interrupts
+// HPETState *s = (HPETState*) opaque;
+// qemu_mod_timer(s->periodic_timer, qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100);
+ } else {
+#ifdef HPET_DEBUG
+ printf("qemu: invalid hpet_write l at %#x = %#x\n", addr, value);
+#endif
+ }
+ break;
+ case 0xf0:
+ s->hpet_counter = (s->hpet_counter & (0xffffffffULL << 32)) | value;
+#ifdef HPET_DEBUG
+ printf("qemu: HPET counter 0xf0 set to %#x -> %#llx\n", value, s->hpet_counter);
+#endif
+ break;
+ case 0xf4:
+ s->hpet_counter = (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
+#ifdef HPET_DEBUG
+ printf("qemu: HPET counter 0xf4 set to %#x -> %#llx\n", value, s->hpet_counter);
+#endif
+ break;
+ default:
+ {
+ uint8_t timer_id = (addr - HPET_BASE - 0x100) / 0x20;
+ switch((addr - HPET_BASE - 0x100) % 0x20) {
+ case 0x0:
+ if(value & 1) break; // reserved
+ s->timer[timer_id].delivery = (value >> 14) & 1;
+ s->timer[timer_id].apic_port = (value >> 9) & 16;
+ s->timer[timer_id].periodic = (value >> 3) & 1;
+ s->timer[timer_id].enabled = (value >> 2) & 1;
+ s->timer[timer_id].type = (value >> 1) & 1;
+#ifdef HPET_DEBUG
+ printf("qemu: hpet_write l at %#x = %#x\n", addr, value);
+#endif
+ hpet_check(&(s->timer[timer_id]));
+ break;
+#ifdef HPET_DEBUG
+ case 0x4: // Interrupt capabilities
+ printf("qemu: invalid hpet_write l at %#x = %#x\n", addr, value);
+ break;
+#endif
+ case 0x8: // comparator register
+ s->timer[timer_id].comparator = value;
+ hpet_check(&(s->timer[timer_id]));
+ break;
+ case 0xc:
+#ifdef HPET_DEBUG
+ printf("qemu: invalid hpet_write l at %#x = %#x\n", addr, value);
+#endif
+ break;
+ }
+ }
+ }
+
+}
+
+static CPUReadMemoryFunc *hpet_ram_read[] = {
+ hpet_ram_readb,
+ hpet_ram_readw,
+ hpet_ram_readl,
+};
+
+static CPUWriteMemoryFunc *hpet_ram_write[] = {
+ hpet_ram_writeb,
+ hpet_ram_writew,
+ hpet_ram_writel,
+};
+
+
+void hpet_init(qemu_irq irq) {
+ int iomemtype, i;
+ HPETState *s;
+
+ /* XXX this is a dirty hack for HPET support w/o LPC
+ Actually this is a config descriptor for the RCBA */
+ s = qemu_mallocz(sizeof(HPETState));
+
+ for(i=0; i<HPET_NUM_TIMERS; i++) {
+ s->timer[i].comparator = 0xffffffff;
+ s->timer[i].state = s;
+ s->timer[i].timer = qemu_new_timer(vm_clock, hpet_timer, s->timer+i);
+ }
+
+ /* HPET Area */
+
+ iomemtype = cpu_register_io_memory(0, hpet_ram_read,
+ hpet_ram_write, s);
+
+ cpu_register_physical_memory(HPET_BASE, 0x400, iomemtype);
+
+ hpet_irq = irq;
+ s->periodic_timer = qemu_new_timer(vm_clock,
+ hpet_periodic_timer, s);
+}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2008-01-08 15:11 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-08 15:22 [Qemu-devel] [PATCH 2/9] HPET device Alexander Graf
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.