Allow unknown NMIs to be propagated to domain0 via new

VIRQ_NMI. Also simplify x86_32 NMI handling -- there's
no need to greedily consume IO/parity errors in
assembly code as they can be deferred without causing
an interrupt storm (the NMI pin is always edge-triggered
even though the sources are level-asserted).

Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
kaf24@firebug.cl.cam.ac.uk committed 2005-12-20 17:55:20 +01:00
1 parent 4cbd6b3272
commit 34c31a402c
7 files changed
+75 -111

No files matched your search

+59 -36
View File
@@ -1074,29 +1074,35 @@ asmlinkage int do_general_protection(struct cpu_user_regs *regs)
return 0;
}
unsigned long nmi_softirq_reason;
static void nmi_softirq(void)
/* Defer dom0 notification to softirq context (unsafe in NMI context). */
static unsigned long nmi_dom0_softirq_reason;
#define NMI_DOM0_PARITY_ERR 0
#define NMI_DOM0_IO_ERR 1
#define NMI_DOM0_UNKNOWN 2
static void nmi_dom0_softirq(void)
{
if ( dom0 == NULL )
return;
if ( test_and_clear_bit(0, &nmi_softirq_reason) )
if ( test_and_clear_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason) )
send_guest_virq(dom0->vcpu[0], VIRQ_PARITY_ERR);
if ( test_and_clear_bit(1, &nmi_softirq_reason) )
if ( test_and_clear_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason) )
send_guest_virq(dom0->vcpu[0], VIRQ_IO_ERR);
if ( test_and_clear_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason) )
send_guest_virq(dom0->vcpu[0], VIRQ_NMI);
}
asmlinkage void mem_parity_error(struct cpu_user_regs *regs)
{
/* Clear and disable the parity-error line. */
outb((inb(0x61)&15)|4,0x61);
switch ( opt_nmi[0] )
{
case 'd': /* 'dom0' */
set_bit(0, &nmi_softirq_reason);
raise_softirq(NMI_SOFTIRQ);
set_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason);
raise_softirq(NMI_DOM0_SOFTIRQ);
case 'i': /* 'ignore' */
break;
default: /* 'fatal' */
@@ -1104,18 +1110,19 @@ asmlinkage void mem_parity_error(struct cpu_user_regs *regs)
printk("\n\nNMI - MEMORY ERROR\n");
fatal_trap(TRAP_nmi, regs);
}
outb((inb(0x61) & 0x0f) | 0x04, 0x61); /* clear-and-disable parity check */
mdelay(1);
outb((inb(0x61) & 0x0b) | 0x00, 0x61); /* enable parity check */
}
asmlinkage void io_check_error(struct cpu_user_regs *regs)
{
/* Clear and disable the I/O-error line. */
outb((inb(0x61)&15)|8,0x61);
switch ( opt_nmi[0] )
{
case 'd': /* 'dom0' */
set_bit(0, &nmi_softirq_reason);
raise_softirq(NMI_SOFTIRQ);
set_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason);
raise_softirq(NMI_DOM0_SOFTIRQ);
case 'i': /* 'ignore' */
break;
default: /* 'fatal' */
@@ -1123,43 +1130,59 @@ asmlinkage void io_check_error(struct cpu_user_regs *regs)
printk("\n\nNMI - I/O ERROR\n");
fatal_trap(TRAP_nmi, regs);
}
outb((inb(0x61) & 0x0f) | 0x08, 0x61); /* clear-and-disable IOCK */
mdelay(1);
outb((inb(0x61) & 0x07) | 0x00, 0x61); /* enable IOCK */
}
static void unknown_nmi_error(unsigned char reason)
{
printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
printk("Dazed and confused, but trying to continue\n");
printk("Do you have a strange power saving mode enabled?\n");
}
static void default_do_nmi(struct cpu_user_regs *regs, unsigned long reason)
{
if ( nmi_watchdog )
nmi_watchdog_tick(regs);
if ( reason & 0x80 )
mem_parity_error(regs);
else if ( reason & 0x40 )
io_check_error(regs);
else if ( !nmi_watchdog )
unknown_nmi_error((unsigned char)(reason&0xff));
switch ( opt_nmi[0] )
{
case 'd': /* 'dom0' */
set_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason);
raise_softirq(NMI_DOM0_SOFTIRQ);
case 'i': /* 'ignore' */
break;
default: /* 'fatal' */
printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
printk("Dazed and confused, but trying to continue\n");
printk("Do you have a strange power saving mode enabled?\n");
}
}
static int dummy_nmi_callback(struct cpu_user_regs *regs, int cpu)
{
return 0;
return 0;
}
static nmi_callback_t nmi_callback = dummy_nmi_callback;
asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason)
asmlinkage void do_nmi(struct cpu_user_regs *regs)
{
unsigned int cpu = smp_processor_id();
unsigned char reason;
++nmi_count(cpu);
if ( !nmi_callback(regs, cpu) )
default_do_nmi(regs, reason);
if ( nmi_callback(regs, cpu) )
return;
if ( nmi_watchdog )
nmi_watchdog_tick(regs);
/* Only the BSP gets external NMIs from the system. */
if ( cpu == 0 )
{
reason = inb(0x61);
if ( reason & 0x80 )
mem_parity_error(regs);
else if ( reason & 0x40 )
io_check_error(regs);
else if ( !nmi_watchdog )
unknown_nmi_error((unsigned char)(reason&0xff));
}
}
void set_nmi_callback(nmi_callback_t callback)
@@ -1169,7 +1192,7 @@ void set_nmi_callback(nmi_callback_t callback)
void unset_nmi_callback(void)
{
nmi_callback = dummy_nmi_callback;
nmi_callback = dummy_nmi_callback;
}
asmlinkage int math_state_restore(struct cpu_user_regs *regs)
@@ -1318,7 +1341,7 @@ void __init trap_init(void)
cpu_init();
open_softirq(NMI_SOFTIRQ, nmi_softirq);
open_softirq(NMI_DOM0_SOFTIRQ, nmi_dom0_softirq);
}
+2 -2
View File
@@ -335,7 +335,7 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs){
extern long evtchn_send(int lport);
extern long do_block(void);
void do_nmi(struct cpu_user_regs *, unsigned long);
void do_nmi(struct cpu_user_regs *);
static int check_vmx_controls(ctrls, msr)
{
@@ -1850,7 +1850,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
break;
}
case TRAP_nmi:
do_nmi(&regs, 0);
do_nmi(&regs);
break;
default:
vmx_reflect_exception(v);
+5 -63
View File
@@ -601,15 +601,7 @@ ENTRY(nmi)
pushl %eax
SAVE_ALL_NOSEGREGS(a)
# Check for hardware problems.
inb $0x61,%al
testb $0x80,%al
jne nmi_parity_err
testb $0x40,%al
jne nmi_io_err
movl %eax,%ebx
# Okay, its almost a normal NMI tick. We can only process it if:
# We can only process the NMI if:
# A. We are the outermost Xen activation (in which case we have
# the selectors safely saved on our stack)
# B. DS and ES contain sane Xen values.
@@ -619,7 +611,7 @@ ENTRY(nmi)
movl UREGS_eflags(%esp),%eax
movb UREGS_cs(%esp),%al
testl $(3|X86_EFLAGS_VM),%eax
jnz do_watchdog_tick
jnz continue_nmi
movl %ds,%eax
cmpw $(__HYPERVISOR_DS),%ax
jne defer_nmi
@@ -627,15 +619,14 @@ ENTRY(nmi)
cmpw $(__HYPERVISOR_DS),%ax
jne defer_nmi
do_watchdog_tick:
continue_nmi:
movl $(__HYPERVISOR_DS),%edx
movl %edx,%ds
movl %edx,%es
movl %esp,%edx
pushl %ebx # reason
pushl %edx # regs
pushl %edx
call do_nmi
addl $8,%esp
addl $4,%esp
jmp ret_from_intr
defer_nmi:
@@ -649,55 +640,6 @@ defer_nmi:
TRAP_deferred_nmi),%ss:APIC_ICR(%eax)
jmp restore_all_xen
nmi_parity_err:
# Clear and disable the parity-error line
andb $0xf,%al
orb $0x4,%al
outb %al,$0x61
cmpb $'i',%ss:opt_nmi # nmi=ignore
je nmi_out
bts $0,%ss:nmi_softirq_reason
bts $NMI_SOFTIRQ,%ss:irq_stat
cmpb $'d',%ss:opt_nmi # nmi=dom0
je nmi_out
movl $(__HYPERVISOR_DS),%edx # nmi=fatal
movl %edx,%ds
movl %edx,%es
movl %esp,%edx
push %edx
call mem_parity_error
addl $4,%esp
nmi_out:movl %ss:UREGS_eflags(%esp),%eax
movb %ss:UREGS_cs(%esp),%al
testl $(3|X86_EFLAGS_VM),%eax
jz restore_all_xen
movl $(__HYPERVISOR_DS),%edx
movl %edx,%ds
movl %edx,%es
GET_CURRENT(%ebx)
jmp test_all_events
nmi_io_err:
# Clear and disable the I/O-error line
andb $0xf,%al
orb $0x8,%al
outb %al,$0x61
cmpb $'i',%ss:opt_nmi # nmi=ignore
je nmi_out
bts $1,%ss:nmi_softirq_reason
bts $NMI_SOFTIRQ,%ss:irq_stat
cmpb $'d',%ss:opt_nmi # nmi=dom0
je nmi_out
movl $(__HYPERVISOR_DS),%edx # nmi=fatal
movl %edx,%ds
movl %edx,%es
movl %esp,%edx
push %edx
call io_check_error
addl $4,%esp
jmp nmi_out
ENTRY(setup_vm86_frame)
# Copies the entire stack frame forwards by 16 bytes.
.macro copy_vm86_words count=18
+2 -2
View File
@@ -160,9 +160,9 @@ asmlinkage void do_double_fault(void)
BUILD_SMP_INTERRUPT(deferred_nmi, TRAP_deferred_nmi)
asmlinkage void smp_deferred_nmi(struct cpu_user_regs regs)
{
asmlinkage void do_nmi(struct cpu_user_regs *, unsigned long);
asmlinkage void do_nmi(struct cpu_user_regs *);
ack_APIC_irq();
do_nmi(&regs, 0);
do_nmi(&regs);
}
void __init percpu_traps_init(void)
+1 -3
View File
@@ -567,9 +567,7 @@ ENTRY(double_fault)
ENTRY(nmi)
pushq $0
SAVE_ALL
inb $0x61,%al
movl %eax,%esi # reason
movq %rsp,%rdi # regs
movq %rsp,%rdi
call do_nmi
jmp restore_all_xen
+5 -4
View File
@@ -67,12 +67,13 @@
*/
#define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */
#define VIRQ_DEBUG 1 /* Request guest to dump debug info. */
#define VIRQ_CONSOLE 2 /* (DOM0) bytes received on emergency console. */
#define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */
#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */
#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error. */
#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error. */
#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error (port 0x61, bit 7). */
#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error (port 0x61, bit 6). */
#define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */
#define NR_VIRQS 7
#define VIRQ_NMI 7 /* (DOM0) Unknown NMI (not from ISA port 0x61).*/
#define NR_VIRQS 8
/*
* MMU-UPDATE REQUESTS
+1 -1
View File
@@ -6,7 +6,7 @@
#define SCHEDULE_SOFTIRQ 1
#define NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ 2
#define KEYPRESS_SOFTIRQ 3
#define NMI_SOFTIRQ 4
#define NMI_DOM0_SOFTIRQ 4
#define PAGE_SCRUB_SOFTIRQ 5
#define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ 6
#define NR_SOFTIRQS 7
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.