New i386 SMP code:

- The MP code no longer knows anything specific about an MP Table.
  Instead, the local APIC code adds CPUs via the cpu_add() function when
  a local APIC is enumerated by an APIC enumerator.
- Don't divide the argument to mp_bootaddress() by 1024 just so that we
  can turn around and mulitply it by 1024 again.
- We no longer panic if SMP is enabled but we are booted on a UP machine.
- init_secondary(), the asm code between init_secondary() and ap_init()
  in mpboot.s and ap_init() have all been merged together in C into
  init_secondary().
- We now use the cpuid feature bits to determine if we should enable
  PSE, PGE, or VME on each AP.
- Due to the change in the implementation of critical sections, acquire
  the SMP TLB mutex around a slightly larger chunk of code for TLB
  shootdowns.
- Remove some of the debug code from the original SMP implementation
  that is no longer used or no longer applies to the new APIC code.
- Use a temporary hack to disable the ACPI module until the SMP code has
  been further reorganized to allow ACPI to work as a module again.
- Add a DDB command to dump the interesting contents of the IDT.
This commit is contained in:
John Baldwin 2003-11-03 22:32:04 +00:00
parent 9738024229
commit 147ad8d5ad
9 changed files with 848 additions and 4176 deletions

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@
#include "opt_pmap.h"
#include <machine/asmacros.h> /* miscellaneous asm macros */
#include <machine/apic.h>
#include <machine/apicreg.h>
#include <machine/specialreg.h>
#include "assym.s"
@ -77,6 +77,32 @@
NON_GPROF_ENTRY(MPentry)
CHECKPOINT(0x36, 3)
/*
* Enable features on this processor. We don't support SMP on
* CPUs older than a Pentium, so we know that we can use the cpuid
* instruction.
*/
movl $1,%eax
cpuid /* Retrieve features */
movl %cr4,%eax
#ifndef DISABLE_PSE
testl $CPUID_PSE,%edx
jz 1f
orl $CR4_PSE,%eax /* Enable PSE */
1:
#endif
#ifndef DISABLE_PG_G
testl $CPUID_PGE,%edx
jz 1f
orl $CR4_PGE,%eax /* Enable PGE */
1:
#endif
testl $CPUID_VME,%edx
jz 1f
orl $CR4_VME,%eax /* Enable VME */
1:
movl %eax,%cr4
/* Now enable paging mode */
#ifdef PAE
movl R(IdlePDPT), %eax
@ -87,22 +113,6 @@ NON_GPROF_ENTRY(MPentry)
#else
movl R(IdlePTD), %eax
movl %eax,%cr3
#endif
#ifndef DISABLE_PSE
cmpl $0, R(pseflag)
je 1f
movl %cr4, %eax
orl $CR4_PSE, %eax
movl %eax, %cr4
1:
#endif
#ifndef DISABLE_PG_G
cmpl $0, R(pgeflag)
je 2f
movl %cr4, %eax
orl $CR4_PGE, %eax
movl %eax, %cr4
2:
#endif
movl %cr0,%eax
orl $CR0_PE|CR0_PG,%eax /* enable paging */
@ -118,32 +128,6 @@ NON_GPROF_ENTRY(MPentry)
mp_begin: /* now running relocated at KERNBASE */
CHECKPOINT(0x37, 4)
call init_secondary /* load i386 tables */
CHECKPOINT(0x38, 5)
/*
* If the [BSP] CPU has support for VME, turn it on.
*/
testl $CPUID_VME, cpu_feature /* XXX WRONG! BSP! */
jz 1f
movl %cr4, %eax
orl $CR4_VME, %eax
movl %eax, %cr4
1:
/* disable the APIC, just to be SURE */
movl lapic+LA_SVR, %eax /* get spurious vector reg. */
andl $~APIC_SVR_SWEN, %eax /* clear software enable bit */
movl %eax, lapic+LA_SVR
/* signal our startup to the BSP */
movl lapic+LA_VER, %eax /* our version reg contents */
movl %eax, cpu_apic_versions /* into [ 0 ] */
incl mp_ncpus /* signal BSP */
CHECKPOINT(0x39, 6)
/* Now, let's prepare for some REAL WORK :-) This doesn't return. */
call ap_init
/*
* This is the embedded trampoline or bootstrap that is

View File

@ -334,5 +334,6 @@ void
db_show_mdpcpu(struct pcpu *pc)
{
db_printf("APIC ID = %d\n", pc->pc_apic_id);
db_printf("currentldt = 0x%x\n", pc->pc_currentldt);
}

View File

@ -40,6 +40,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_apic.h"
#include "opt_atalk.h"
#include "opt_compat.h"
#include "opt_cpu.h"
@ -92,7 +93,10 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/cons.h>
#ifdef DDB
#include <ddb/ddb.h>
#include <ddb/db_sym.h>
#endif
#include <net/netisr.h>
@ -102,6 +106,7 @@ __FBSDID("$FreeBSD$");
#include <machine/clock.h>
#include <machine/specialreg.h>
#include <machine/bootinfo.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/pc/bios.h>
#include <machine/pcb_ext.h> /* pcb.h included via sys/user.h */
@ -114,8 +119,10 @@ __FBSDID("$FreeBSD$");
#include <machine/smp.h>
#endif
#ifdef DEV_ISA
#include <i386/isa/icu.h>
#include <i386/isa/intr_machdep.h>
#endif
#include <isa/rtc.h>
#include <machine/vm86.h>
#include <sys/ptrace.h>
@ -150,7 +157,7 @@ static void fill_fpregs_xmm(struct savexmm *, struct save87 *);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL)
int _udatasel, _ucodesel;
u_int atdevbase;
u_int atdevbase, basemem;
int cold = 1;
@ -224,10 +231,7 @@ cpu_startup(dummy)
bufinit();
vm_pager_bufferinit();
#ifndef SMP
/* For SMP, we delay the cpu_setregs() until after SMP startup. */
cpu_setregs();
#endif
}
/*
@ -1467,6 +1471,31 @@ extern inthand_t
IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align),
IDTVEC(xmm), IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall);
#ifdef DDB
/*
* Display the index and function name of any IDT entries that don't use
* the default 'rsvd' entry point.
*/
DB_SHOW_COMMAND(idt, db_show_idt)
{
struct gate_descriptor *ip;
int idx, quit;
uintptr_t func;
ip = idt;
db_setup_paging(db_simple_pager, &quit, DB_LINES_PER_PAGE);
for (idx = 0, quit = 0; idx < NIDT; idx++) {
func = (ip->gd_hioffset << 16 | ip->gd_looffset);
if (func != (uintptr_t)&IDTVEC(rsvd)) {
db_printf("%3d\t", idx);
db_printsym(func, DB_STGY_PROC);
db_printf("\n");
}
ip++;
}
}
#endif
void
sdtossd(sd, ssd)
struct segment_descriptor *sd;
@ -1501,7 +1530,7 @@ getmemsize(int first)
{
int i, physmap_idx, pa_indx;
int hasbrokenint12;
u_int basemem, extmem;
u_int extmem;
struct vm86frame vmf;
struct vm86context vmc;
vm_paddr_t pa, physmap[PHYSMAP_SIZE];
@ -1719,10 +1748,7 @@ next_run: ;
#ifdef SMP
/* make hole for AP bootstrap code */
physmap[1] = mp_bootaddress(physmap[1] / 1024);
/* look for the MP hardware - needed for apic addresses */
i386_mp_probe();
physmap[1] = mp_bootaddress(physmap[1]);
#endif
/*
@ -2065,7 +2091,7 @@ init386(first)
printf("WARNING: loader(8) metadata is missing!\n");
#ifdef DEV_ISA
isa_defaultirq();
atpic_startup();
#endif
#ifdef DDB
@ -2157,6 +2183,8 @@ init386(first)
void
cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
{
pcpu->pc_acpi_id = 0xffffffff;
}
#if defined(I586_CPU) && !defined(NO_F00F_HACK)
@ -2720,6 +2748,10 @@ Debugger(const char *msg)
}
#endif /* no DDB */
#ifndef DEV_ACPI
MODULE_VERSION(acpi, 1);
#endif
#ifdef DDB
/*

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@
#include "opt_pmap.h"
#include <machine/asmacros.h> /* miscellaneous asm macros */
#include <machine/apic.h>
#include <machine/apicreg.h>
#include <machine/specialreg.h>
#include "assym.s"
@ -77,6 +77,32 @@
NON_GPROF_ENTRY(MPentry)
CHECKPOINT(0x36, 3)
/*
* Enable features on this processor. We don't support SMP on
* CPUs older than a Pentium, so we know that we can use the cpuid
* instruction.
*/
movl $1,%eax
cpuid /* Retrieve features */
movl %cr4,%eax
#ifndef DISABLE_PSE
testl $CPUID_PSE,%edx
jz 1f
orl $CR4_PSE,%eax /* Enable PSE */
1:
#endif
#ifndef DISABLE_PG_G
testl $CPUID_PGE,%edx
jz 1f
orl $CR4_PGE,%eax /* Enable PGE */
1:
#endif
testl $CPUID_VME,%edx
jz 1f
orl $CR4_VME,%eax /* Enable VME */
1:
movl %eax,%cr4
/* Now enable paging mode */
#ifdef PAE
movl R(IdlePDPT), %eax
@ -87,22 +113,6 @@ NON_GPROF_ENTRY(MPentry)
#else
movl R(IdlePTD), %eax
movl %eax,%cr3
#endif
#ifndef DISABLE_PSE
cmpl $0, R(pseflag)
je 1f
movl %cr4, %eax
orl $CR4_PSE, %eax
movl %eax, %cr4
1:
#endif
#ifndef DISABLE_PG_G
cmpl $0, R(pgeflag)
je 2f
movl %cr4, %eax
orl $CR4_PGE, %eax
movl %eax, %cr4
2:
#endif
movl %cr0,%eax
orl $CR0_PE|CR0_PG,%eax /* enable paging */
@ -118,32 +128,6 @@ NON_GPROF_ENTRY(MPentry)
mp_begin: /* now running relocated at KERNBASE */
CHECKPOINT(0x37, 4)
call init_secondary /* load i386 tables */
CHECKPOINT(0x38, 5)
/*
* If the [BSP] CPU has support for VME, turn it on.
*/
testl $CPUID_VME, cpu_feature /* XXX WRONG! BSP! */
jz 1f
movl %cr4, %eax
orl $CR4_VME, %eax
movl %eax, %cr4
1:
/* disable the APIC, just to be SURE */
movl lapic+LA_SVR, %eax /* get spurious vector reg. */
andl $~APIC_SVR_SWEN, %eax /* clear software enable bit */
movl %eax, lapic+LA_SVR
/* signal our startup to the BSP */
movl lapic+LA_VER, %eax /* our version reg contents */
movl %eax, cpu_apic_versions /* into [ 0 ] */
incl mp_ncpus /* signal BSP */
CHECKPOINT(0x39, 6)
/* Now, let's prepare for some REAL WORK :-) This doesn't return. */
call ap_init
/*
* This is the embedded trampoline or bootstrap that is

View File

@ -136,12 +136,9 @@ __FBSDID("$FreeBSD$");
#include <machine/cputypes.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
#if defined(SMP) || defined(APIC_IO)
#ifdef SMP
#include <machine/smp.h>
#include <machine/apic.h>
#include <machine/segments.h>
#include <machine/tss.h>
#endif /* SMP || APIC_IO */
#endif
#define PMAP_KEEP_PDIRS
#ifndef PMAP_SHPGPERPROC
@ -391,16 +388,6 @@ pmap_bootstrap(firstaddr, loadaddr)
/* Turn on PG_G on kernel page(s) */
pmap_set_pg();
#ifdef SMP
if (cpu_apic_address == 0)
panic("pmap_bootstrap: no local apic! (non-SMP hardware?)");
/* local apic is mapped on last page */
SMPpt[NPTEPG - 1] = (pt_entry_t)(PG_V | PG_RW | PG_N | pgeflag |
(cpu_apic_address & PG_FRAME));
#endif
invltlb();
}
/*
@ -603,11 +590,17 @@ pmap_invalidate_page(pmap_t pmap, vm_offset_t va)
u_int cpumask;
u_int other_cpus;
critical_enter();
if (smp_started) {
if (!(read_eflags() & PSL_I))
panic("%s: interrupts disabled", __func__);
mtx_lock_spin(&smp_tlb_mtx);
} else
critical_enter();
/*
* We need to disable interrupt preemption but MUST NOT have
* interrupts disabled here.
* XXX we may need to hold schedlock to get a coherent pm_active
* XXX critical sections disable interrupts again
*/
if (pmap == kernel_pmap || pmap->pm_active == all_cpus) {
invlpg(va);
@ -620,7 +613,10 @@ pmap_invalidate_page(pmap_t pmap, vm_offset_t va)
if (pmap->pm_active & other_cpus)
smp_masked_invlpg(pmap->pm_active & other_cpus, va);
}
critical_exit();
if (smp_started)
mtx_unlock_spin(&smp_tlb_mtx);
else
critical_exit();
}
void
@ -630,11 +626,17 @@ pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
u_int other_cpus;
vm_offset_t addr;
critical_enter();
if (smp_started) {
if (!(read_eflags() & PSL_I))
panic("%s: interrupts disabled", __func__);
mtx_lock_spin(&smp_tlb_mtx);
} else
critical_enter();
/*
* We need to disable interrupt preemption but MUST NOT have
* interrupts disabled here.
* XXX we may need to hold schedlock to get a coherent pm_active
* XXX critical sections disable interrupts again
*/
if (pmap == kernel_pmap || pmap->pm_active == all_cpus) {
for (addr = sva; addr < eva; addr += PAGE_SIZE)
@ -650,7 +652,10 @@ pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
smp_masked_invlpg_range(pmap->pm_active & other_cpus,
sva, eva);
}
critical_exit();
if (smp_started)
mtx_unlock_spin(&smp_tlb_mtx);
else
critical_exit();
}
void
@ -659,11 +664,17 @@ pmap_invalidate_all(pmap_t pmap)
u_int cpumask;
u_int other_cpus;
critical_enter();
if (smp_started) {
if (!(read_eflags() & PSL_I))
panic("%s: interrupts disabled", __func__);
mtx_lock_spin(&smp_tlb_mtx);
} else
critical_enter();
/*
* We need to disable interrupt preemption but MUST NOT have
* interrupts disabled here.
* XXX we may need to hold schedlock to get a coherent pm_active
* XXX critical sections disable interrupts again
*/
if (pmap == kernel_pmap || pmap->pm_active == all_cpus) {
invltlb();
@ -676,7 +687,10 @@ pmap_invalidate_all(pmap_t pmap)
if (pmap->pm_active & other_cpus)
smp_masked_invltlb(pmap->pm_active & other_cpus);
}
critical_exit();
if (smp_started)
mtx_unlock_spin(&smp_tlb_mtx);
else
critical_exit();
}
#else /* !SMP */
/*

View File

@ -15,17 +15,7 @@
#ifdef _KERNEL
#if defined(SMP) && defined(I386_CPU) && !defined(COMPILING_LINT)
#error SMP not supported with I386_CPU
#endif
#if defined(SMP) && !defined(APIC_IO)
# error APIC_IO required for SMP, add "options APIC_IO" to your config file.
#endif /* SMP && !APIC_IO */
#if defined(SMP) && defined(CPU_DISABLE_CMPXCHG) && !defined(COMPILING_LINT)
#error SMP not supported with CPU_DISABLE_CMPXCHG
#endif
#if defined(SMP) || defined(APIC_IO)
#ifdef SMP
#ifndef LOCORE
@ -43,25 +33,10 @@ extern int current_postcode; /** XXX currently in mp_machdep.c */
current_postcode |= (((X) << 4) & 0xf0), \
outb(0x80, current_postcode)
#include <sys/bus.h> /* XXX */
#include <machine/apic.h>
#include <sys/bus.h>
#include <machine/frame.h>
#include <i386/isa/icu.h>
#include <i386/isa/intr_machdep.h>
/*
* Interprocessor interrupts for SMP.
*/
#define IPI_INVLTLB XINVLTLB_OFFSET
#define IPI_INVLPG XINVLPG_OFFSET
#define IPI_INVLRNG XINVLRNG_OFFSET
#define IPI_LAZYPMAP XLAZYPMAP_OFFSET
#define IPI_RENDEZVOUS XRENDEZVOUS_OFFSET
#define IPI_AST XCPUAST_OFFSET
#define IPI_STOP XCPUSTOP_OFFSET
#define IPI_HARDCLOCK XHARDCLOCK_OFFSET
#define IPI_STATCLOCK XSTATCLOCK_OFFSET
#include <machine/intr_machdep.h>
#include <machine/apicvar.h>
/* global data in mpboot.s */
extern int bootMP_size;
@ -70,61 +45,36 @@ extern int bootMP_size;
void bootMP(void);
/* global data in mp_machdep.c */
extern int bsp_apic_ready;
extern int mp_naps;
extern int mp_nbusses;
extern int mp_napics;
extern int mp_picmode;
extern int boot_cpu_id;
extern vm_offset_t cpu_apic_address;
extern vm_offset_t io_apic_address[];
extern u_int32_t cpu_apic_versions[];
extern u_int32_t *io_apic_versions;
extern int cpu_num_to_apic_id[];
extern int io_num_to_apic_id[];
extern int apic_id_to_logical[];
#define APIC_INTMAPSIZE 32
struct apic_intmapinfo {
int ioapic;
int int_pin;
volatile void *apic_address;
int redirindex;
};
extern struct apic_intmapinfo int_to_apicintpin[];
extern struct pcb stoppcbs[];
extern struct mtx smp_tlb_mtx;
/* IPI handlers */
inthand_t
IDTVEC(invltlb), /* TLB shootdowns - global */
IDTVEC(invlpg), /* TLB shootdowns - 1 page */
IDTVEC(invlrng), /* TLB shootdowns - page range */
IDTVEC(hardclock), /* Forward hardclock() */
IDTVEC(statclock), /* Forward statclock() */
IDTVEC(cpuast), /* Additional software trap on other cpu */
IDTVEC(cpustop), /* CPU stops & waits to be restarted */
IDTVEC(rendezvous), /* handle CPU rendezvous */
IDTVEC(lazypmap); /* handle lazy pmap release */
/* functions in mp_machdep.c */
void i386_mp_probe(void);
u_int mp_bootaddress(u_int);
u_int isa_apic_mask(u_int);
int isa_apic_irq(int);
int pci_apic_irq(int, int, int);
int apic_irq(int, int);
int next_apic_irq(int);
int undirect_isa_irq(int);
int undirect_pci_irq(int);
int apic_bus_type(int);
int apic_src_bus_id(int, int);
int apic_src_bus_irq(int, int);
int apic_int_type(int, int);
int apic_trigger(int, int);
int apic_polarity(int, int);
int mp_grab_cpu_hlt(void);
void assign_apic_irq(int apic, int intpin, int irq);
void revoke_apic_irq(int irq);
void bsp_apic_configure(void);
void cpu_add(u_int apic_id, char boot_cpu);
void init_secondary(void);
void forward_statclock(void);
void forwarded_statclock(struct clockframe frame);
void forward_hardclock(void);
void forwarded_hardclock(struct clockframe frame);
void ipi_selected(u_int cpus, u_int ipi);
void ipi_all(u_int ipi);
void ipi_all_but_self(u_int ipi);
void ipi_self(u_int ipi);
#ifdef APIC_INTR_REORDER
void set_lapic_isrloc(int, int);
#endif /* APIC_INTR_REORDER */
void forward_statclock(void);
void forwarded_statclock(struct clockframe frame);
void forward_hardclock(void);
void forwarded_hardclock(struct clockframe frame);
u_int mp_bootaddress(u_int);
int mp_grab_cpu_hlt(void);
void smp_invlpg(vm_offset_t addr);
void smp_masked_invlpg(u_int mask, vm_offset_t addr);
void smp_invlpg_range(vm_offset_t startva, vm_offset_t endva);
@ -133,30 +83,8 @@ void smp_masked_invlpg_range(u_int mask, vm_offset_t startva,
void smp_invltlb(void);
void smp_masked_invltlb(u_int mask);
/* global data in mpapic.c */
extern volatile lapic_t lapic;
extern volatile ioapic_t **ioapic;
/* functions in mpapic.c */
void apic_dump(char*);
void apic_initialize(void);
void imen_dump(void);
int apic_ipi(int, int, int);
int selected_apic_ipi(u_int, int, int);
int io_apic_setup(int);
void io_apic_setup_intpin(int, int);
void io_apic_set_id(int, int);
int io_apic_get_id(int);
int ext_int_setup(int, int);
void set_apic_timer(int);
int read_apic_timer(void);
void u_sleep(int);
u_int io_apic_read(int, int);
void io_apic_write(int, int, u_int);
#endif /* !LOCORE */
#endif /* SMP && !APIC_IO */
#endif /* SMP */
#endif /* _KERNEL */
#endif /* _MACHINE_SMP_H_ */

View File

@ -33,14 +33,6 @@
* Various 'tests in progress' and configuration parameters.
*/
/*
* Put FAST_INTR() ISRs at an APIC priority above the regular INTs.
* Allow the mp_lock() routines to handle FAST interrupts while spinning.
*/
#define FAST_HI
/*
* These defines enable critical region locking of areas that were
* protected via cli/sti in the UP kernel.
@ -59,39 +51,12 @@
*/
#define CPUSTOP_ON_DDBBREAK
#ifdef APIC_IO
/*
* Don't assume that slow interrupt handler X is called from vector
* X + ICU_OFFSET.
*/
#define APIC_INTR_REORDER
#endif /* APIC_IO */
/*
* Misc. counters.
*
#define COUNT_XINVLTLB_HITS
*/
/**
* Hack to "fake-out" kernel into thinking it is running on a 'default config'.
*
* value == default type
#define TEST_DEFAULT_CONFIG 6
*/
/*
* Simple test code for IPI interaction, save for future...
*
#define TEST_TEST1
#define IPI_TARGET_TEST1 1
*/
/*
* Address of POST hardware port.
* Defining this enables POSTCODE macros.