From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JCG6Y-0007gR-NG for qemu-devel@nongnu.org; Tue, 08 Jan 2008 10:11:02 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JCG6X-0007eV-K6 for qemu-devel@nongnu.org; Tue, 08 Jan 2008 10:11:02 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JCG6X-0007eH-97 for qemu-devel@nongnu.org; Tue, 08 Jan 2008 10:11:01 -0500 Received: from kassel160.server4you.de ([62.75.246.160] helo=csgraf.de) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1JCG6W-0007kA-Hb for qemu-devel@nongnu.org; Tue, 08 Jan 2008 10:11:01 -0500 Received: from [10.10.102.8] (charybdis-ext.suse.de [195.135.221.2]) by csgraf.de (Postfix) with ESMTP id E48803A8A for ; Tue, 8 Jan 2008 16:10:58 +0100 (CET) Message-ID: <47839543.5020904@csgraf.de> Date: Tue, 08 Jan 2008 16:22:43 +0100 From: Alexander Graf MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------060905020306040407020100" Subject: [Qemu-devel] [PATCH 2/9] HPET device Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org This is a multi-part message in MIME format. --------------060905020306040407020100 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit 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. --------------060905020306040407020100 Content-Type: text/x-patch; name="qemu-hpet.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="qemu-hpet.patch" 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; itimer[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; itimer[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); +} --------------060905020306040407020100--