From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JkiLR-0007tg-1b for qemu-devel@nongnu.org; Sat, 12 Apr 2008 12:12:49 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JkiLQ-0007sq-EG for qemu-devel@nongnu.org; Sat, 12 Apr 2008 12:12:48 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JkiLQ-0007sc-4j for qemu-devel@nongnu.org; Sat, 12 Apr 2008 12:12:48 -0400 Received: from fmmailgate02.web.de ([217.72.192.227]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1JkiLP-0006iE-Is for qemu-devel@nongnu.org; Sat, 12 Apr 2008 12:12:48 -0400 Received: from smtp06.web.de (fmsmtp06.dlan.cinetic.de [172.20.5.172]) by fmmailgate02.web.de (Postfix) with ESMTP id 1E4D7D89BB96 for ; Sat, 12 Apr 2008 18:12:47 +0200 (CEST) Received: from [88.65.46.55] (helo=[192.168.1.198]) by smtp06.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.109 #226) id 1JkiLO-0005cd-00 for qemu-devel@nongnu.org; Sat, 12 Apr 2008 18:12:46 +0200 Message-ID: <4800DF7E.7070000@web.de> Date: Sat, 12 Apr 2008 18:12:46 +0200 From: Jan Kiszka MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="------------enig11F619CECE57F61A45202506" Sender: jan.kiszka@web.de Subject: [Qemu-devel] [PATCH 3/3] x86: Rework local IRQ delivery for APICs 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 an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enig11F619CECE57F61A45202506 Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: quoted-printable [ Refreshed and resent version of http://permalink.gmane.org/gmane.comp.emulators.qemu/23456 ] This patch reworks the delivery of IRQs directed to a local APIC, handling all requests in a central function, apic_local_deliver(), analogue to apic_bus_deliver(). Futhermore, the APIC_LVT_LINT0 mask initialization is fixed for SMP. Finally, virtual routing of the legacy PIT to the APICs is adopted in so far that pic_irq_request() delivers interrupts through the LINT0 lines of all APICs in the system. This routing allows for emulating the IO-APIC NMI watchdog mechanism, including on SMP, which Linux exploits via its nmi_watchdog=3D1. Signed-off-by: Jan Kiszka --- hw/apic.c | 63 ++++++++++++++++++++++++++++++++++++++++++-------------= ------- hw/pc.c | 15 ++++++++++---- hw/pc.h | 3 ++ 3 files changed, 57 insertions(+), 24 deletions(-) Index: b/hw/apic.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- a/hw/apic.c +++ b/hw/apic.c @@ -166,6 +166,37 @@ static inline void reset_bit(uint32_t *t tab[i] &=3D ~mask; } =20 +void apic_local_deliver(CPUState *env, int vector) +{ + APICState *s =3D env->apic_state; + uint32_t lvt =3D s->lvt[vector]; + int trigger_mode; + + if (lvt & APIC_LVT_MASKED) + return; + + switch ((lvt >> 8) & 7) { + case APIC_DM_SMI: + cpu_interrupt(env, CPU_INTERRUPT_SMI); + break; + + case APIC_DM_NMI: + cpu_interrupt(env, CPU_INTERRUPT_NMI); + break; + + case APIC_DM_EXTINT: + cpu_interrupt(env, CPU_INTERRUPT_HARD); + break; + + case APIC_DM_FIXED: + trigger_mode =3D APIC_TRIGGER_EDGE; + if ((vector =3D=3D APIC_LVT_LINT0 || vector =3D=3D APIC_LVT_LINT= 1) && + (lvt & APIC_LVT_LEVEL_TRIGGER)) + trigger_mode =3D APIC_TRIGGER_LEVEL; + apic_set_irq(s, lvt & 0xff, trigger_mode); + } +} + #define foreach_apic(apic, deliver_bitmask, code) \ {\ int __i, __j, __mask;\ @@ -502,10 +533,8 @@ int apic_accept_pic_intr(CPUState *env) =20 lvt0 =3D s->lvt[APIC_LVT_LINT0]; =20 - if (s->id =3D=3D 0 && - ((s->apicbase & MSR_IA32_APICBASE_ENABLE) =3D=3D 0 || - ((lvt0 & APIC_LVT_MASKED) =3D=3D 0 && - ((lvt0 >> 8) & 0x7) =3D=3D APIC_DM_EXTINT))) + if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) =3D=3D 0 || + (lvt0 & APIC_LVT_MASKED) =3D=3D 0) return 1; =20 return 0; @@ -556,9 +585,7 @@ static void apic_timer(void *opaque) { APICState *s =3D opaque; =20 - if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { - apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE= ); - } + apic_local_deliver(s->cpu_env, APIC_LVT_TIMER); apic_timer_update(s, s->next_time); } =20 @@ -821,12 +848,14 @@ static void apic_reset(void *opaque) APICState *s =3D opaque; apic_init_ipi(s); =20 - /* - * LINT0 delivery mode is set to ExtInt at initialization time - * typically by BIOS, so PIC interrupt can be delivered to the - * processor when local APIC is enabled. - */ - s->lvt[APIC_LVT_LINT0] =3D 0x700; + if (s->id =3D=3D 0) { + /* + * LINT0 delivery mode on CPU #0 is set to ExtInt at initializat= ion + * time typically by BIOS, so PIC interrupt can be delivered to = the + * processor when local APIC is enabled. + */ + s->lvt[APIC_LVT_LINT0] =3D 0x700; + } } =20 static CPUReadMemoryFunc *apic_mem_read[3] =3D { @@ -851,19 +880,13 @@ int apic_init(CPUState *env) if (!s) return -1; env->apic_state =3D s; - apic_init_ipi(s); s->id =3D last_apic_id++; env->cpuid_apic_id =3D s->id; s->cpu_env =3D env; s->apicbase =3D 0xfee00000 | (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; =20 - /* - * LINT0 delivery mode is set to ExtInt at initialization time - * typically by BIOS, so PIC interrupt can be delivered to the - * processor when local APIC is enabled. - */ - s->lvt[APIC_LVT_LINT0] =3D 0x700; + apic_reset(s); =20 /* XXX: mapping more APICs at the same memory location */ if (apic_io_memory =3D=3D 0) { Index: b/hw/pc.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- a/hw/pc.c +++ b/hw/pc.c @@ -113,9 +113,16 @@ int cpu_get_pic_interrupt(CPUState *env) =20 static void pic_irq_request(void *opaque, int irq, int level) { - CPUState *env =3D opaque; - if (level && apic_accept_pic_intr(env)) - cpu_interrupt(env, CPU_INTERRUPT_HARD); + CPUState *env =3D first_cpu; + + if (!level) + return; + + while (env) { + if (apic_accept_pic_intr(env)) + apic_local_deliver(env, APIC_LINT0); + env =3D env->next_cpu; + } } =20 /* PC cmos mappings */ @@ -845,7 +852,7 @@ static void pc_init1(int ram_size, int v if (linux_boot) load_linux(kernel_filename, initrd_filename, kernel_cmdline); =20 - cpu_irq =3D qemu_allocate_irqs(pic_irq_request, first_cpu, 1); + cpu_irq =3D qemu_allocate_irqs(pic_irq_request, NULL, 1); i8259 =3D i8259_init(cpu_irq[0]); ferr_irq =3D i8259[13]; =20 Index: b/hw/pc.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- a/hw/pc.h +++ b/hw/pc.h @@ -39,8 +39,11 @@ void irq_info(void); /* APIC */ typedef struct IOAPICState IOAPICState; =20 +#define APIC_LINT0 3 + int apic_init(CPUState *env); int apic_accept_pic_intr(CPUState *env); +void apic_local_deliver(CPUState *env, int vector); int apic_get_interrupt(CPUState *env); IOAPICState *ioapic_init(void); void ioapic_set_irq(void *opaque, int vector, int level); --------------enig11F619CECE57F61A45202506 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.4-svn0 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iD8DBQFIAN9+niDOoMHTA+kRAkcqAJ0YjINd2wmpETOQnOPLlYD0/lvbLgCfTSB6 2hmHgIUmTrFM/1U0rfXYdK8= =b+wZ -----END PGP SIGNATURE----- --------------enig11F619CECE57F61A45202506--