Date: Mon, 9 Sep 1996 18:43:16 -0600 (MDT) From: smp@csn.net To: FreeBSD-gnats-submit@freebsd.org Subject: kern/1594: SMP kernel fix 960909.4 Message-ID: <199609100043.SAA04080@rick.systemsix.com> Resent-Message-ID: <199609100050.RAA02151@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 1594
>Category: kern
>Synopsis: apic_startup() needs work
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: freebsd-bugs
>State: open
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Mon Sep 9 17:50:01 PDT 1996
>Last-Modified:
>Originator: Steve Passe
>Organization:
New Ideas
>Release: FreeBSD 2.2-CURRENT i386
>Environment:
smp-sys as of August 27, 1996
>Description:
The current version of apic_startup() does not properly
start the 2nd CPU on an Intel XXPRESS box. Experimentation
shows that it can be re-written in such a way as to be more
robust and support a wider range of motherboards. The current
version appears to follow the pseudo code in example B-1 of the
MP spec v1.4, page B3. The example appears to be incorrect
and part of the problem. Specifically it shows an APIC STARTUP
IPI twice in a row, while databooks and the MP spec claim this
should only be done ONCE after a RESET IPI or hard reset.
Secondly, some hardware (eg the XXPRESS) depends on the
INIT/RESET IPI to actually start the 2nd CPU via the BIOS
warm-start vector mechanism. The current code ignores the
fact that the INIT/RESET IPI depends on a valid warm-start
vector.
This code needs further refinement to deal with motherboards
that depend on discrete APICs, as they don't support the
STARTUP IPI. I believe this includes 80486 class mbs.
apic_probe() would have to be extended to determine
such facts and leave info around for apic_startup().
To deal with the XXPRESS's need for the funky 'WARMBOOT_TO_BOOTSTRAP'
one could parse the "PRODUCT_ID_STRING" in the mpfps for "XXPRESS"
and act accordingly. (what a kludge)
The basic algorithm:
if ( AP's local APIC == discrete ) /* eg. 80486 with 80489 */
{
INIT_RESET_IPI( toBootMP );
}
else if ( rogueHardware ) /* eg. Intel XXPRESS */
{
INIT_RESET_IPI( toBootMP );
}
else /* APIC == embedded */ /* eg. 586/686 */
{
INIT_RESET_IPI( toHlt );
}
if ( AP's local APIC == embedded ) /* eg. 586/686 */
{
STARTUP_IPI( bootMPVector );
}
>How-To-Repeat:
run current code on Intel XXPRESS box.
>Fix:
[ I created several defines in smpasm.h to conditionalize code: ]
/*
* defining this will cause a warm-start vector to the bootMP
* code to be built and installed, NOT the preferred method!
*
* Rogue hardware known to need this define:
* Intel XXPRESS motherboard.
* possibly any hardware with discrete APIC support (80486?)
*
#define WARMBOOT_TO_BOOTSTRAP
*/
/*
* defines needed for the code:
*/
#define WARMBOOT_OFF 0xf0000467
#define WARMBOOT_SEG 0xf0000469
#define CMOS_REG 0x70
#define CMOS_DATA 0x71
#define BIOS_RESET 0x0f
#define BIOS_WARM 0x0a
[ it is necessary to restore the warm-boot vector to its original
value after starting the 2nd CPU.
modify machdep.s, at top and bottom of cpu_startup(), add: ]
cpu_startup(dummy)
void *dummy;
{
extern int mpbioswarmvec, mpbiosreason;
...
/* restore the original warm-boot information */
*(u_long*)(KERNBASE+0x0467) = mpbioswarmvec;
outb( 0x70, 0x0f );
outb( 0x71, (u_char)(mpbiosreason & 0xff) );
}
[ create entry point in i386/i386/mpboot.s for the warmstart @ line 139: ]
NON_GPROF_ENTRY(haltpoint)
dead: hlt /* We should never get here */
[ the new code for apic_startup in i386/i386/mpcore.s ]
NON_GPROF_ENTRY(apic_startup)
/*
* this version of apic_startup (more or less) complies to the MP spec v1.4
*/
movl _mpenabled, %eax /* See if the probe succeeded */
cmpl $1, %eax
jz 1f
ret /* SMP not enabled */
1:
pushl %esi
pushl %ebx
call _get_mplock
/* create a BIOS warm-start vector to a 'HLT' instruction */
movl WARMBOOT_OFF,%eax
movl %eax,_mpbioswarmvec
#if defined( WARMBOOT_TO_BOOTSTRAP ) /* this is for rogue hardware */
movw $0,WARMBOOT_OFF /* store offset */
#else
lea _haltpoint,%eax
subl $_bootMP,%eax /* calculate offset */
movw %ax,WARMBOOT_OFF /* store offset */
#endif /* WARMBOOT_TO_BOOTSTRAP */
movl $MP_INITADDR,%eax /* get 32bit address */
shrl $4,%eax /* convert to segment */
movw %ax,WARMBOOT_SEG /* store segment */
/* place "warm-start" value in CMOS ram for BIOS */
cli /* disable INTs */
movb $BIOS_RESET,%al /* address of "reason" */
outb %al,$CMOS_REG
inb $CMOS_DATA,%al /* read current value */
movl %eax,_mpbiosreason /* save it for later */
movb $BIOS_RESET,%al /* address of "reason" */
outb %al,$CMOS_REG
movb $BIOS_WARM,%al /* "warm" thru (40:67) */
outb %al,$CMOS_DATA /* store it */
sti /* re-enable INTs */
movl _apic_base, %esi
/* Step 1 - Do a INIT/Reset seqeuence */
movl APIC_ICR_HI(%esi),%eax
andl $0xf0ffffff,%eax /* mask out ID bits */
orl $CPUNBR,%eax
movl %eax,APIC_ICR_HI(%esi)
movl APIC_ICR_LOW(%esi),%eax
andl $0xfff00000,%eax
orl $0x0000c500,%eax /* do a INIT IPI - ASSERT/RESET */
movl %eax,APIC_ICR_LOW(%esi)
1: movl APIC_ICR_LOW(%esi),%eax /* wait for pending status end */
andl $0x00001000,%eax
jnz 1b
xorl %ebx, %ebx
movl $0x10000, %eax /* Delay a bit */
2: decl %eax
cmpl %eax, %ebx
jnz 2b
movl APIC_ICR_HI(%esi),%eax
andl $0xf0ffffff,%eax /* mask out ID bits */
orl $CPUNBR,%eax
movl %eax,APIC_ICR_HI(%esi)
movl APIC_ICR_LOW(%esi),%eax
andl $0xfff00000,%eax
orl $0x00008500,%eax /* do a INIT IPI - DEASSERT/RESET */
movl %eax,APIC_ICR_LOW(%esi)
3: movl APIC_ICR_LOW(%esi),%eax /* wait for pending status end */
andl $0x00001000,%eax
jnz 3b
/* Step 2 - Do the STARTUP IPI sequence */
xorl %ebx, %ebx
movl $0x10000, %eax /* Delay a bit */
1: decl %eax
cmpl %eax, %ebx
jnz 1b
2: movl APIC_ICR_LOW(%esi),%eax /* wait for pending status end */
andl $0x00001000,%eax
jnz 2b
movl APIC_ICR_HI(%esi),%eax
andl $0xf0ffffff,%eax /* mask out ID bits */
orl $CPUNBR,%eax
movl %eax,APIC_ICR_HI(%esi)
movl APIC_ICR_LOW(%esi),%eax
andl $0xfff00000,%eax
orl $0x0000069f,%eax /* do a STARTUP IPI */
movl %eax,APIC_ICR_LOW(%esi)
xorl %ebx, %ebx
movl $0x1000000, %eax /* Delay a bit */
3: decl %eax
cmpl %eax, %ebx
jnz 3b
4: movl APIC_ICR_LOW(%esi),%eax /* wait for pending status end */
andl $0x00001000,%eax
jnz 4b
popl %ebx
popl %esi
ret
>Audit-Trail:
>Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199609100043.SAA04080>
