Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 04 Jun 2005 20:51:38 -0600 (MDT)
From:      "M. Warner Losh" <imp@bsdimp.com>
To:        dipjyoti.saikia@gmail.com
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: NMI handlers ??
Message-ID:  <20050604.205138.89664988.imp@bsdimp.com>
In-Reply-To: <dcbc809d05060310185eeeb436@mail.gmail.com>
References:  <dcbc809d05060310185eeeb436@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
In message: <dcbc809d05060310185eeeb436@mail.gmail.com>
            Dipjyoti Saikia <dipjyoti.saikia@gmail.com> writes:
: I am working on IPMI watchdog implementation . The problem that I am
: facing is that in case of improper system shutdown or  powerfail the
: watchdog keeps running and the next time system boots up , BIOS
: complains of FRB2 timeout and fails one of the CPU's ( Working on SMP
: system ) .
: 
: My idea is to handle NMI generated by abruptly pushing power button
: and disabling the timer in the routine.
: 
: Can we have a handlers for NMI ?? I am not very sure what is happening
: inside the kernel when NMI is delivered .
: 
: Please provide me some inputs.

We did this at timing solutions.  Here are a few notes:

(1) You must disable the F00F_HACK with the kernel config file.
(2) We had to hack the nmi code to allow multiple refiring of the nmi
    routine in the chipset.  These hacks are evidentially fairly
    chipset specific.  We were using the #IOCHK line on the ISA bus to
    accomplish this.  I don't think that you'll need to worry about
    this.
(3) You need some kind of NMI handler.  You can do almost nothing in
    this handler.  The following code is from 4.x.  nmiReset is set
    elsewhere.

#include <machine/asmacros.h>			/* miscellaneous macros */
#include <sys/cdefs.h>				/* CPP macros */

/* XXX: not very portable! */
#define KDSEL	0x10				/* kernel data selector */

	.text
	ALIGN_TEXT

	.globl Xtscnmidrv
Xtscnmidrv:
	pushl	%eax
	pushl	%ecx
	pushl	%edx
	pushl	%ds
	movl	$KDSEL, %eax
	movl	%eax, %ds
	
	/* read the timestamp counter */
	.byte   0x0f, 0x31      /* RDTSC */
	movl	%edx, tsHi
	movl	%eax, tsLo

	/* update the counter */
	incl	nmiCounter

	/*
	 * XXX:	It is necessary to drop the NMI level on the driving
	 *	card at this point IF we wish to use 'NMI_CREATE_EDGE'
	 */

	.globl nmiReset
	movl	nmiReset, %eax
	testl	%eax, %eax
	/* XXX:	we should really just permanently disable NMIs in this case */
	je	skip
	call	*%eax
skip:
	/* diddle the IOCHK# NMI registers */
	inb	$0x61, %al		/* current PORT-B contents */
	/* XXX:	 need to test source bits, assume IOCHK# for now... */
	andb	$0x0f, %al		/* PIIX wants upper bits 0 on write */
	orb	$0x08, %al		/* IOCHK# high to clear */
	outb	%al, $0x61
	andb	$0x07, %al		/* IOCHK# low to enable */
	outb	%al, $0x61

	/* restore registers */
	popl	%ds
	popl	%edx
	popl	%ecx
	popl	%eax
	iret

	.data
	ALIGN_DATA

	.globl nmiCounter
nmiCounter:
	.long	0

	.globl timeStamp
timeStamp:	
tsLo:
	.long	0
tsHi:
	.long	0

4) We have to establish the handler:
    /* Install the custom TSC NMI handler. */
    setidt( 2, &IDTVEC(tscnmidrv), SDT_SYS386IGT,
           SEL_KPL, GSEL(GCODE_SEL, SEL_KPL) );

and set nmiReset when you arm the nmi source and clear it if you ever
disarm it.  nmiReset should be set to the function you want to call.
I'm not sure what the right sequence of inb/outb is for your
chipset...

Warner





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050604.205138.89664988.imp>