Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 25 Jun 1997 20:32:35 -0600
From:      Steve Passe <smp@csn.net>
To:        Christopher Ulbright <ulbright@cs.washington.edu>
Cc:        freebsd-smp@FreeBSD.ORG
Subject:   Re: Debugger 
Message-ID:  <199706260232.UAA17883@Ilsa.StevesCafe.com>
In-Reply-To: Your message of "Wed, 25 Jun 1997 09:50:19 PDT." <Pine.OSF.3.96.970625094314.9321B-100000@sanjuan.cs.washington.edu> 

next in thread | previous in thread | raw e-mail | index | archive | help
Hi,

  some suggested pseudo-code follows.  please comment.

------------------------------------- cut -------------------------------------

---
/*
 * example usage:
 */
breakpoint()
{
...
	stop_other_cpus(cpu_map);

	do_stuff();

	restart_other_cpus(stopped_cpus);
...
}


---
i386/include/smp.h:

/* global data in i386/isa/apic_vector.s: */
extern volatile u_int stopped_cpus;
extern volatile u_int started_cpus;
extern u_int cpu_map;


---
i386/isa/intr_machdep.h:

#define XCPUSTOP_OFFSET	33
inthand_t
	Xcpustop;


---
i386/i386/mp_machdep.c:

/*
 * existing functions:
 */

mp_enable(u_int boot_addr)
{
...
#if defined( APIC_IO )
...
+	/* install an inter-CPU IPI for CPU stop/restart */
+	setidt(ICU_OFFSET + XCPUSTOP_OFFSET, Xcpustop,
+	       SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
#endif  /* APIC_IO */
...
}


start_all_aps(u_int boot_addr)
{
...
	/* start each AP */
	for (x = 1; x <= mp_naps; ++x) {
...
+		cpu_map |= (1 << x);		/* record AP in global map */
	}
...
+	cpu_map |= 1;				/* record BSP in global map */
}


/*
 * new functions:
 */

/*
 * When called the executing CPU will send an IPI to all other CPUs
 *  requesting that they halt execution.
 *
 * Usually (but not necessarily) called with 'cpu_map' as its arg.
 *
 *  - Signals all CPUs in map to stop.
 *  - Waits for each to stop.
 *
 * Returns:
 *  -1: error
 *   0: NA
 *   1: ok
 *
 * XXX FIXME: this is not MP-safe, needs a lock to prevent multiple CPUs
 *            from executing at same time.
 */
int
stop_other_cpus( u_int map )
{
	if (!smp_active)
		return 0;

	stopped_cpus = 0;
	map &= ~(1 << cpuid);			/* clear our bit */

	/* send IPI to all CPUs in map */
	selected_apic_ipi(map,
			  ICU_OFFSET + XSTOP_CPUS_OFFSET,
			  APIC_DELMODE_FIXED);

	while (stopped_cpus != map)
		/* spin */ ;

	return 1;
}


/*
 * Called by a CPU to restart stopped CPUs. 
 *
 * Usually (but not necessarily) called with 'stopped_cpus' as its arg.
 *
 *  - Signals all CPUs in map to restart.
 *  - Waits for each to restart.
 *
 * Returns:
 *  -1: error
 *   0: NA
 *   1: ok
 */
int
restart_other_cpus( u_int map )
{
	if (!smp_active)
		return 0;

	map &= ~(1 << cpuid);		/* XXX paranoia */
	started_cpus = map;		/* signal other cpus to restart */

	while (started_cpus)		/* wait for each to clear its bit */
		/* spin */ ;

	return 1;
}


---
i386/isa/apic_vector.s:

	.globl _stopped_cpus
_stopped_cpus:
	.long	0

	.globl _started_cpus
_started_cpus:
	.long	0

	.globl _cpu_map
_cpu_map:
	.long	0

/*
 * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
 *
 *  - Signals its receipt.
 *  - Waits for permission to restart.
 *  - Signals its restart.
 */
	.text
	SUPERALIGN_TEXT
	.globl _Xcpustop
_Xcpustop:
	pushl	%eax
	pushl	%ds			/* save current data segment */

	movl	$KDSEL, %eax
	movl	%ax, %ds		/* use KERNEL data segment */

	movl	_cpuid, %eax		/* id */

	lock
	btsl	%eax, _stopped_cpus	/* stopped_cpus |= (1<<id) */
1:
	btl	%eax, _started_cpus	/* while (!(started_cpus & (1<<id))) */
	jnc	1b

	lock
	btrl	%eax, _started_cpus	/* started_cpus &= ~(1<<id) */

	popl	%ds			/* restore previous data segment */
	popl	%eax

	iret
------------------------------------- cut -------------------------------------

--
Steve Passe	| powered by 
smp@csn.net	|            Symmetric MultiProcessor FreeBSD





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