On 16/12/2015 11:28, Gonglei (Arei) wrote: > I'll move the global nmi_disabled into RTCState, then I have to add a global > RTCState > Variable so that other C files can use the rtc_state->external_nmi_disabled.
Hmm, I think it should be done differently. This is a layering violation, the NMI_EN is essentially a pin (qemu_irq) between the ISA bridges and the RTC. The NMI "button" is also a component of the ISA bridge; you should not need to touch anything except the RTC and the ISA bridges, in particular not the APICs. First, you need to add a qemu_irq argument to rtc_init. The RTC can raise/lower the IRQ on writes to port 0x70. Second, make the ISA bridges implement NMIState, where the implementation of NMIState is similar to inject_nmi in hw/core/nmi.c: CPU_FOREACH(cs) { X86CPU *cpu = X86_CPU(cs); if (!cpu->apic_state) { cpu_interrupt(cs, CPU_INTERRUPT_NMI); } else { apic_deliver_nmi(cpu->apic_state); } } Third, the ISA bridges (hw/isa/piix4.c and hw/isa/lpc_ich9.c) need to export a qemu_irq for nmi_en IRQ (e.g. using qdev_init_gpio_in_named), and you should modify the ISA bridge's implementation of NMIState to latch the NMI if you send one while NMIs are disabled. The nmi_en IRQ can also trigger an NMI when nmi_en is enabled and an NMI was latched. The nmi_en status and NMI latch status must be migrated in a new subsection of the ISA bridges. Fourth, the PC machines should use qdev_get_gpio_in_named to retrieve the qemu_irq from the ISA bridges, and pass it to pc_basic_device_init. I may have messed up some steps, but this is the basic idea. Paolo