change log for rtems (2011-07-14)

rtems-vc at rtems.org rtems-vc at rtems.org
Thu Jul 14 17:10:13 UTC 2011


 *jennifer*:
2011-07-14	Jennifer Averett <Jennifer.Averett at OARcorp.com>

	* shared/irq/apic.h, shared/smp/README, shared/smp/smp-imps.c,
	shared/smp/smp-imps.h: New files.

M   1.81  c/src/lib/libbsp/i386/ChangeLog
A    1.1  c/src/lib/libbsp/i386/shared/irq/apic.h
A    1.1  c/src/lib/libbsp/i386/shared/smp/README
A    1.1  c/src/lib/libbsp/i386/shared/smp/smp-imps.h
A    1.1  c/src/lib/libbsp/i386/shared/smp/smp-imps.c

diff -u rtems/c/src/lib/libbsp/i386/ChangeLog:1.80 rtems/c/src/lib/libbsp/i386/ChangeLog:1.81
--- rtems/c/src/lib/libbsp/i386/ChangeLog:1.80	Wed May 25 01:23:49 2011
+++ rtems/c/src/lib/libbsp/i386/ChangeLog	Thu Jul 14 11:50:21 2011
@@ -1,3 +1,8 @@
+2011-07-14	Jennifer Averett <Jennifer.Averett at OARcorp.com>
+
+	* shared/irq/apic.h, shared/smp/README, shared/smp/smp-imps.c,
+	shared/smp/smp-imps.h: New files.
+
 2011-05-25	Ralf Corsépius <ralf.corsepius at rtems.org>
 
 	* shared/comm/tty_drv.c, shared/comm/tty_drv.h:

diff -u /dev/null rtems/c/src/lib/libbsp/i386/shared/irq/apic.h:1.1
--- /dev/null	Thu Jul 14 12:10:13 2011
+++ rtems/c/src/lib/libbsp/i386/shared/irq/apic.h	Thu Jul 14 11:50:21 2011
@@ -0,0 +1,86 @@
+/*
+ *  <Insert copyright here : it must be BSD-like so everyone can use it>
+ *
+ *  Author:  Erich Boleyn  <erich at uruk.org>   http://www.uruk.org/~erich/
+ *
+ *  Header file for Intel Architecture local and I/O APIC definitions.
+ *
+ *  This file was created from information in the Intel Pentium Pro
+ *  Family Developer's Manual, Volume 3: Operating System Writer's
+ *  Manual, order number 242692-001, which can be ordered from the
+ *  Intel literature center.
+ */
+
+#ifndef _APIC_H
+#define _APIC_H
+
+/*
+ *  APIC Defines.
+ */
+
+/*
+ * Recommendation:  Don't use this except for MSI interrupt delivery.
+ * In general, the "Destination Mode" can be used to control this, since
+ * it is DIFFERENT (0xF) for Pentium and P6, but not on the same APIC
+ * version for AMD Opteron.
+ */
+#define APIC_BCAST_ID			       	0xFF
+
+/*
+ *  APIC register definitions
+ */
+
+/*
+ *  Shared defines for I/O and local APIC definitions
+ */
+/* APIC version register */
+#define	APIC_VERSION(x)				((x) & 0xFF)
+#define	APIC_MAXREDIR(x)			(((x) >> 16) & 0xFF)
+/* APIC id register */
+#define	APIC_ID(x)				((x) >> 24)
+#define APIC_VER_NEW				0x10
+
+#define IOAPIC_REGSEL				0
+#define IOAPIC_RW				0x10
+#define		IOAPIC_ID			0
+#define		IOAPIC_VER			1
+#define		IOAPIC_REDIR			0x10
+
+#define LAPIC_ID				0x20
+#define LAPIC_VER				0x30
+#define LAPIC_TPR				0x80
+#define LAPIC_APR				0x90
+#define LAPIC_PPR				0xA0
+#define LAPIC_EOI				0xB0
+#define LAPIC_LDR				0xD0
+#define LAPIC_DFR				0xE0
+#define LAPIC_SPIV				0xF0
+#define		LAPIC_SPIV_ENABLE_APIC		0x100
+#define LAPIC_ISR				0x100
+#define LAPIC_TMR				0x180
+#define LAPIC_IRR				0x200
+#define LAPIC_ESR				0x280
+#define LAPIC_ICR				0x300
+#define		LAPIC_ICR_DS_SELF		0x40000
+#define		LAPIC_ICR_DS_ALLINC		0x80000
+#define		LAPIC_ICR_DS_ALLEX		0xC0000
+#define		LAPIC_ICR_TM_LEVEL		0x8000
+#define		LAPIC_ICR_LEVELASSERT		0x4000
+#define		LAPIC_ICR_STATUS_PEND		0x1000
+#define		LAPIC_ICR_DM_LOGICAL		0x800
+#define		LAPIC_ICR_DM_LOWPRI		0x100
+#define		LAPIC_ICR_DM_SMI		0x200
+#define		LAPIC_ICR_DM_NMI		0x400
+#define		LAPIC_ICR_DM_INIT		0x500
+#define		LAPIC_ICR_DM_SIPI		0x600
+#define LAPIC_LVTT				0x320
+#define LAPIC_LVTPC		       		0x340
+#define LAPIC_LVT0				0x350
+#define LAPIC_LVT1				0x360
+#define LAPIC_LVTE				0x370
+#define LAPIC_TICR				0x380
+#define LAPIC_TCCR				0x390
+#define LAPIC_TDCR				0x3E0
+
+#endif  /* _APIC_H */
+

diff -u /dev/null rtems/c/src/lib/libbsp/i386/shared/smp/README:1.1
--- /dev/null	Thu Jul 14 12:10:13 2011
+++ rtems/c/src/lib/libbsp/i386/shared/smp/README	Thu Jul 14 11:50:22 2011
@@ -0,0 +1,14 @@
+#
+# $Id$
+#
+
+The following files were developed by  Erich Boleyn  <erich at uruk.org>.
+The original files were copied from http://www.uruk.org/mps/ and committed
+into cvs as is.  These files will be modified for RTEMS smp support,
+but the original files are being commited in order to track any file
+changes that occur.  We are attempting to keep these changes as minimal
+and conainted as possible.
+
+  + smp-imps.c
+  + smp-imps.h
+  + ../irq/apic.h

diff -u /dev/null rtems/c/src/lib/libbsp/i386/shared/smp/smp-imps.h:1.1
--- /dev/null	Thu Jul 14 12:10:13 2011
+++ rtems/c/src/lib/libbsp/i386/shared/smp/smp-imps.h	Thu Jul 14 11:50:22 2011
@@ -0,0 +1,227 @@
+/*
+ *  <Insert copyright here : it must be BSD-like so everyone can use it>
+ *
+ *  Author:  Erich Boleyn  <erich at uruk.org>   http://www.uruk.org/~erich/
+ *
+ *  Header file implementing Intel MultiProcessor Specification (MPS)
+ *  version 1.1 and 1.4 SMP hardware control for Intel Architecture CPUs,
+ *  with hooks for running correctly on a standard PC without the hardware.
+ *
+ *  This file was created from information in the Intel MPS version 1.4
+ *  document, order number 242016-004, which can be ordered from the
+ *  Intel literature center.
+ */
+
+#ifndef _SMP_IMPS_H
+#define _SMP_IMPS_H
+
+/* make sure "apic.h" is included */
+#ifndef _APIC_H
+#error		Must include "apic.h" before "smp-imps.h"
+#endif  /* !_APIC_H */
+
+/*
+ *  Defines used.
+ */
+
+#define IMPS_READ(x)	(*((volatile unsigned *) (x)))
+#define IMPS_WRITE(x,y)	(*((volatile unsigned *) (x)) = (y))
+
+#ifdef IMPS_DEBUG
+#define IMPS_DEBUG_PRINT(x)  KERNEL_PRINT(x)
+#else  /* !IMPS_DEBUG */
+#define IMPS_DEBUG_PRINT(x)
+#endif /* !IMPS_DEBUG */
+
+#define IMPS_MAX_CPUS			APIC_BCAST_ID
+
+/*
+ *  This is the value that must be in the "sig" member of the MP
+ *  Floating Pointer Structure.
+ */
+#define IMPS_FPS_SIGNATURE	('_' | ('M'<<8) | ('P'<<16) | ('_'<<24))
+#define IMPS_FPS_IMCRP_BIT	0x80
+#define IMPS_FPS_DEFAULT_MAX	7
+
+/*
+ *  This is the value that must be in the "sig" member of the MP
+ *  Configuration Table Header.
+ */
+#define IMPS_CTH_SIGNATURE	('P' | ('C'<<8) | ('M'<<16) | ('P'<<24))
+
+/*
+ *  These are the "type" values for Base MP Configuration Table entries.
+ */
+#define		IMPS_FLAG_ENABLED	1
+#define IMPS_BCT_PROCESSOR		0
+#define		IMPS_CPUFLAG_BOOT	2
+#define IMPS_BCT_BUS			1
+#define IMPS_BCT_IOAPIC			2
+#define IMPS_BCT_IO_INTERRUPT		3
+#define IMPS_BCT_LOCAL_INTERRUPT	4
+#define		IMPS_INT_INT		0
+#define		IMPS_INT_NMI		1
+#define		IMPS_INT_SMI		2
+#define		IMPS_INT_EXTINT		3
+
+
+/*
+ *  Typedefs and data item definitions done here.
+ */
+
+typedef struct imps_fps imps_fps;	/* MP floating pointer structure */
+typedef struct imps_cth imps_cth;	/* MP configuration table header */
+typedef struct imps_processor imps_processor;
+typedef struct imps_bus imps_bus;
+typedef struct imps_ioapic imps_ioapic;
+typedef struct imps_interrupt imps_interrupt;
+
+
+/*
+ *  Data structures defined here
+ */
+
+/*
+ *  MP Floating Pointer Structure (fps)
+ *
+ *  Look at page 4-3 of the MP spec for the starting definitions of
+ *  this structure.
+ */
+struct imps_fps
+{
+	unsigned sig;
+	imps_cth *cth_ptr;
+	unsigned char length;
+	unsigned char spec_rev;
+	unsigned char checksum;
+	unsigned char feature_info[5];
+};
+
+/*
+ *  MP Configuration Table Header  (cth)
+ *
+ *  Look at page 4-5 of the MP spec for the starting definitions of
+ *  this structure.
+ */
+struct imps_cth
+{
+	unsigned sig;
+	unsigned short base_length;
+	unsigned char spec_rev;
+	unsigned char checksum;
+	char oem_id[8];
+	char prod_id[12];
+	unsigned oem_table_ptr;
+	unsigned short oem_table_size;
+	unsigned short entry_count;
+	unsigned lapic_addr;
+	unsigned short extended_length;
+	unsigned char extended_checksum;
+	char reserved[1];
+};
+
+/*
+ *  Base MP Configuration Table Types.  They are sorted according to
+ *  type (i.e. all of type 0 come first, etc.).  Look on page 4-6 for
+ *  the start of the descriptions.
+ */
+
+struct imps_processor
+{
+	unsigned char type;			/* must be 0 */
+	unsigned char apic_id;
+	unsigned char apic_ver;
+	unsigned char flags;
+	unsigned signature;
+	unsigned features;
+	char reserved[8];
+};
+
+struct imps_bus
+{
+	unsigned char type;			/* must be 1 */
+	unsigned char id;
+	char bus_type[6];
+};
+
+struct imps_ioapic
+{
+	unsigned char type;			/* must be 2 */
+	unsigned char id;
+	unsigned char ver;
+	unsigned char flags;
+	unsigned addr;
+};
+
+struct imps_interrupt
+{
+	unsigned char type;			/* must be 3 or 4 */
+	unsigned char int_type;
+	unsigned short flags;
+	unsigned char source_bus_id;
+	unsigned char source_bus_irq;
+	unsigned char dest_apic_id;
+	unsigned char dest_apic_intin;
+};
+
+
+/*
+ *  Exported globals here.
+ */
+
+/*
+ *  "imps_enabled" is non-zero if the probe sequence found IMPS
+ *  information and was successful.
+ */
+extern int imps_enabled;
+
+/*
+ *  This contains the local APIC hardware address.
+ */
+extern unsigned imps_lapic_addr;
+
+/*
+ *  This represents the number of CPUs found.
+ */
+extern int imps_num_cpus;
+
+/*
+ *  These map from virtual cpu numbers to APIC id's and back.
+ */
+extern unsigned char imps_cpu_apic_map[IMPS_MAX_CPUS];
+extern unsigned char imps_apic_cpu_map[IMPS_MAX_CPUS];
+
+
+/*
+ *  This is the primary function for probing for Intel MPS 1.1/1.4
+ *  compatible hardware and BIOS information.  While probing the CPUs
+ *  information returned from the BIOS, this also starts up each CPU
+ *  and gets it ready for use.
+ *
+ *  Call this during the early stages of OS startup, before memory can
+ *  be messed up.
+ *
+ *  Returns N if IMPS information was found (for number of CPUs started)
+ *  and is valid, else 0.
+ */
+
+int imps_probe(void);
+
+/*
+ *  This one is used as a "force" function.  Give it the number of CPUs
+ *  to start, and it will assume a certain number and try it.
+ */
+
+int imps_force(int ncpus);
+
+
+/*
+ *  Defines that use variables
+ */
+
+#define IMPS_LAPIC_READ(x)  (*((volatile unsigned *) (imps_lapic_addr+(x))))
+#define IMPS_LAPIC_WRITE(x, y)   \
+   (*((volatile unsigned *) (imps_lapic_addr+(x))) = (y))
+
+#endif  /* !_SMP_IMPS_H */
+

diff -u /dev/null rtems/c/src/lib/libbsp/i386/shared/smp/smp-imps.c:1.1
--- /dev/null	Thu Jul 14 12:10:13 2011
+++ rtems/c/src/lib/libbsp/i386/shared/smp/smp-imps.c	Thu Jul 14 11:50:22 2011
@@ -0,0 +1,649 @@
+/*
+ *  <Insert copyright here : it must be BSD-like so anyone can use it>
+ *
+ *  Author:  Erich Boleyn  <erich at uruk.org>   http://www.uruk.org/~erich/
+ *
+ *  Source file implementing Intel MultiProcessor Specification (MPS)
+ *  version 1.1 and 1.4 SMP hardware control for Intel Architecture CPUs,
+ *  with hooks for running correctly on a standard PC without the hardware.
+ *
+ *  This file was created from information in the Intel MPS version 1.4
+ *  document, order number 242016-004, which can be ordered from the
+ *  Intel literature center.
+ *
+ *  General limitations of this code:
+ *
+ *   (1) : This code has never been tested on an MPS-compatible system with
+ *           486 CPUs, but is expected to work.
+ *   (2) : Presumes "int", "long", and "unsigned" are 32 bits in size, and
+ *	     that 32-bit pointers and memory addressing is used uniformly.
+ */
+
+#define _SMP_IMPS_C
+
+
+/*
+ *  XXXXX  The following absolutely must be defined!!!
+ *
+ *  The "KERNEL_PRINT" could be made a null macro with no danger, of
+ *  course, but pretty much nothing would work without the other
+ *  ones defined.
+ */
+
+#if 0
+#define KERNEL_PRINT(x)		/* some kind of print function */
+#define CMOS_WRITE_BYTE(x,y)	/* write unsigned char "y" at CMOS loc "x" */
+#define CMOS_READ_BYTE(x)	/* read unsigned char at CMOS loc "x" */
+#define PHYS_TO_VIRTUAL(x)	/* convert physical address "x" to virtual */
+#define VIRTUAL_TO_PHYS(x)	/* convert virtual address "x" to physical */
+#define UDELAY(x)		/* delay roughly at least "x" microsecs */
+#define TEST_BOOTED(x)		/* test bootaddr x to see if CPU started */
+#define READ_MSR_LO(x)		/* Read MSR low function */
+#endif
+
+
+/*
+ *  Includes here
+ */
+
+#define IMPS_DEBUG
+
+#include "apic.h"
+#include "smp-imps.h"
+
+
+/*
+ *  Defines that are here so as not to be in the global header file.
+ */
+#define EBDA_SEG_ADDR			0x40E
+#define BIOS_RESET_VECTOR		0x467
+#define LAPIC_ADDR_DEFAULT		0xFEE00000uL
+#define IOAPIC_ADDR_DEFAULT		0xFEC00000uL
+#define CMOS_RESET_CODE			0xF
+#define		CMOS_RESET_JUMP		0xa
+#define CMOS_BASE_MEMORY		0x15
+
+
+/*
+ *  Static defines here for SMP use.
+ */
+
+#define DEF_ENTRIES	23
+
+static int lapic_dummy = 0;
+static struct {
+	imps_processor proc[2];
+	imps_bus bus[2];
+	imps_ioapic ioapic;
+	imps_interrupt intin[16];
+	imps_interrupt lintin[2];
+} defconfig = {
+	{ { IMPS_BCT_PROCESSOR, 0, 0, 0, 0, 0},
+	  { IMPS_BCT_PROCESSOR, 1, 0, 0, 0, 0} },
+	{ { IMPS_BCT_BUS, 0, {'E', 'I', 'S', 'A', ' ', ' '}},
+	  { 255, 1, {'P', 'C', 'I', ' ', ' ', ' '}} },
+	{ IMPS_BCT_IOAPIC, 0, 0, IMPS_FLAG_ENABLED, IOAPIC_ADDR_DEFAULT },
+	{ { IMPS_BCT_IO_INTERRUPT, IMPS_INT_EXTINT, 0, 0, 0, 0xFF, 0},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 1, 0xFF, 1},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 0, 0xFF, 2},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 3, 0xFF, 3},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 4, 0xFF, 4},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 5, 0xFF, 5},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 6, 0xFF, 6},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 7, 0xFF, 7},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 8, 0xFF, 8},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 9, 0xFF, 9},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 10, 0xFF, 10},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 11, 0xFF, 11},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 12, 0xFF, 12},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 13, 0xFF, 13},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 14, 0xFF, 14},
+	  { IMPS_BCT_IO_INTERRUPT, IMPS_INT_INT, 0, 0, 15, 0xFF, 15} },
+	{ { IMPS_BCT_LOCAL_INTERRUPT, IMPS_INT_EXTINT, 0, 0, 15, 0xFF, 0},
+	  { IMPS_BCT_LOCAL_INTERRUPT, IMPS_INT_NMI, 0, 0, 15, 0xFF, 1} }
+};
+
+/*
+ *  Exported globals here.
+ */
+
+volatile int imps_release_cpus = 0;
+int imps_enabled = 0;
+int imps_num_cpus = 1;
+unsigned imps_lapic_addr = ((unsigned)(&lapic_dummy)) - LAPIC_ID;
+unsigned char imps_cpu_apic_map[IMPS_MAX_CPUS];
+unsigned char imps_apic_cpu_map[IMPS_MAX_CPUS];
+
+
+/*
+ *  MPS checksum function
+ *
+ *  Function finished.
+ */
+
+static int
+get_checksum(unsigned start, int length)
+{
+	unsigned sum = 0;
+
+	while (length-- > 0) {
+		sum += *((unsigned char *) (start++));
+	}
+
+	return (sum&0xFF);
+}
+
+
+/*
+ *  APIC ICR write and status check function.
+ */
+
+static int
+send_ipi(unsigned int dst, unsigned int v)
+{
+	int to, send_status;
+
+	IMPS_LAPIC_WRITE(LAPIC_ICR+0x10, (dst << 24));
+	IMPS_LAPIC_WRITE(LAPIC_ICR, v);
+
+	/* Wait for send to finish */
+	to = 0;
+	do {
+		UDELAY(100);
+		send_status = IMPS_LAPIC_READ(LAPIC_ICR) & LAPIC_ICR_STATUS_PEND;
+	} while (send_status && (to++ < 1000));
+
+	return (to < 1000);
+}
+
+
+/*
+ *  Primary function for booting individual CPUs.
+ *
+ *  This must be modified to perform whatever OS-specific initialization
+ *  that is required.
+ */
+
+static int
+boot_cpu(imps_processor *proc)
+{
+	int apicid = proc->apic_id, success = 1, to;
+	unsigned bootaddr, accept_status;
+	unsigned bios_reset_vector = PHYS_TO_VIRTUAL(BIOS_RESET_VECTOR);
+
+	/*
+	 * Copy boot code for secondary CPUs here.  Find it in between
+	 * "patch_code_start" and "patch_code_end" symbols.  The other CPUs
+	 * will start there in 16-bit real mode under the 1MB boundary.
+	 * "patch_code_start" should be placed at a 4K-aligned address
+	 * under the 1MB boundary.
+	 */
+
+	extern char patch_code_start[];
+	extern char patch_code_end[];
+	bootaddr = (512-64)*1024;
+	memcpy((char *)bootaddr, patch_code_start, patch_code_end - patch_code_start);
+
+	/*
+	 *  Generic CPU startup sequence starts here.
+	 */
+
+	/* set BIOS reset vector */
+	CMOS_WRITE_BYTE(CMOS_RESET_CODE, CMOS_RESET_JUMP);
+	*((volatile unsigned *) bios_reset_vector) = ((bootaddr & 0xFF000) << 12);
+
+	/* clear the APIC error register */
+	IMPS_LAPIC_WRITE(LAPIC_ESR, 0);
+	accept_status = IMPS_LAPIC_READ(LAPIC_ESR);
+
+	/* assert INIT IPI */
+	send_ipi(apicid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_LEVELASSERT | LAPIC_ICR_DM_INIT);
+
+	UDELAY(10000);
+
+	/* de-assert INIT IPI */
+	send_ipi(apicid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_DM_INIT);
+
+	UDELAY(10000);
+
+	/*
+	 *  Send Startup IPIs if not an old pre-integrated APIC.
+	 */
+
+	if (proc->apic_ver >= APIC_VER_NEW) {
+		int i;
+		for (i = 1; i <= 2; i++) {
+			send_ipi(apicid, LAPIC_ICR_DM_SIPI | ((bootaddr >> 12) & 0xFF));
+			UDELAY(1000);
+		}
+	}
+
+	/*
+	 *  Check to see if other processor has started.
+	 */
+	to = 0;
+	while (!TEST_BOOTED(bootaddr) && to++ < 100)
+		UDELAY(10000);
+	if (to >= 100) {
+		KERNEL_PRINT(("CPU Not Responding, DISABLED"));
+		success = 0;
+	} else {
+		KERNEL_PRINT(("#%d  Application Processor (AP)", imps_num_cpus));
+	}
+
+	/*
+	 *  Generic CPU startup sequence ends here, the rest is cleanup.
+	 */
+
+	/* clear the APIC error register */
+	IMPS_LAPIC_WRITE(LAPIC_ESR, 0);
+	accept_status = IMPS_LAPIC_READ(LAPIC_ESR);
+
+	/* clean up BIOS reset vector */
+	CMOS_WRITE_BYTE(CMOS_RESET_CODE, 0);
+	*((volatile unsigned *) bios_reset_vector) = 0;
+
+	KERNEL_PRINT(("\n"));
+
+	return success;
+}
+
+
+/*
+ *  read bios stuff and fill tables
+ */
+
+static void
+add_processor(imps_processor *proc)
+{
+	int apicid = proc->apic_id;
+
+	KERNEL_PRINT(("  Processor [APIC id %d ver %d]:  ",
+		      apicid, proc->apic_ver));
+	if (!(proc->flags & IMPS_FLAG_ENABLED)) {
+		KERNEL_PRINT(("DISABLED\n"));
+		return;
+	}
+	if (proc->flags & (IMPS_CPUFLAG_BOOT)) {
+		KERNEL_PRINT(("#0  BootStrap Processor (BSP)\n"));
+		return;
+	}
+	if (boot_cpu(proc)) {
+
+		/*  XXXXX  add OS-specific setup for secondary CPUs here */
+
+		imps_cpu_apic_map[imps_num_cpus] = apicid;
+		imps_apic_cpu_map[apicid] = imps_num_cpus;
+		imps_num_cpus++;
+	}
+}
+
+
+static void
+add_bus(imps_bus *bus)
+{
+	char str[8];
+
+	memcpy(str, bus->bus_type, 6);
+	str[6] = 0;
+	KERNEL_PRINT(("  Bus id %d is %s\n", bus->id, str));
+
+	/*  XXXXX  add OS-specific code here */
+}
+
+static void
+add_ioapic(imps_ioapic *ioapic)
+{
+	KERNEL_PRINT(("  I/O APIC id %d ver %d, address: 0x%x  ",
+		      ioapic->id, ioapic->ver, ioapic->addr));
+	if (!(ioapic->flags & IMPS_FLAG_ENABLED)) {
+		KERNEL_PRINT(("DISABLED\n"));
+		return;
+	}
+	KERNEL_PRINT(("\n"));
+
+	/*  XXXXX  add OS-specific code here */
+}
+
+
+static void
+imps_read_config_table(unsigned start, int count)
+{
+	while (count-- > 0) {
+		switch (*((unsigned char *)start)) {
+		case IMPS_BCT_PROCESSOR:
+			add_processor((imps_processor *)start);
+			start += 12;	/* 20 total */
+			break;
+		case IMPS_BCT_BUS:
+			add_bus((imps_bus *)start);
+			break;
+		case IMPS_BCT_IOAPIC:
+			add_ioapic((imps_ioapic *)start);
+			break;
+#if 0	/*  XXXXX  uncomment this if "add_io_interrupt" is implemented */
+		case IMPS_BCT_IO_INTERRUPT:
+			add_io_interrupt((imps_interrupt *)start);
+			break;
+#endif
+#if 0	/*  XXXXX  uncomment this if "add_local_interrupt" is implemented */
+		case IMPS_BCT_LOCAL_INTERRUPT:
+			add_local_interupt((imps_interrupt *)start);
+			break;
+#endif
+		default:
+			break;
+		}
+		start += 8;
+	}
+}
+
+
+static int
+imps_bad_bios(imps_fps *fps_ptr)
+{
+	int sum;
+	imps_cth *local_cth_ptr
+		= (imps_cth *) PHYS_TO_VIRTUAL(fps_ptr->cth_ptr);
+
+	if (fps_ptr->feature_info[0] > IMPS_FPS_DEFAULT_MAX) {
+		KERNEL_PRINT(("    Invalid MP System Configuration type %d\n",
+			      fps_ptr->feature_info[0]));
+		return 1;
+	}
+
+	if (fps_ptr->cth_ptr) {
+		sum = get_checksum((unsigned)local_cth_ptr,
+                                   local_cth_ptr->base_length);
+		if (local_cth_ptr->sig != IMPS_CTH_SIGNATURE || sum) {
+			KERNEL_PRINT(("    Bad MP Config Table sig 0x%x and/or checksum 0x%x\n", (unsigned)(fps_ptr->cth_ptr), sum));
+			return 1;
+		}
+		if (local_cth_ptr->spec_rev != fps_ptr->spec_rev) {
+			KERNEL_PRINT(("    Bad MP Config Table sub-revision # %d\n", local_cth_ptr->spec_rev));
+			return 1;
+		}
+		if (local_cth_ptr->extended_length) {
+			sum = (get_checksum(((unsigned)local_cth_ptr)
+					    + local_cth_ptr->base_length,
+					    local_cth_ptr->extended_length)
+			       + local_cth_ptr->extended_checksum) & 0xFF;
+			if (sum) {
+				KERNEL_PRINT(("    Bad Extended MP Config Table checksum 0x%x\n", sum));
+				return 1;
+			}
+		}
+	} else if (!fps_ptr->feature_info[0]) {
+		KERNEL_PRINT(("    Missing configuration information\n"));
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static void
+imps_read_bios(imps_fps *fps_ptr)
+{
+	int apicid;
+	unsigned cth_start, cth_count;
+	imps_cth *local_cth_ptr
+		= (imps_cth *)PHYS_TO_VIRTUAL(fps_ptr->cth_ptr);
+	char *str_ptr;
+
+	KERNEL_PRINT(("Intel MultiProcessor Spec 1.%d BIOS support detected\n",
+		      fps_ptr->spec_rev));
+
+	/*
+	 *  Do all checking of errors which would definitely
+	 *  lead to failure of the SMP boot here.
+	 */
+
+	if (imps_bad_bios(fps_ptr)) {
+		KERNEL_PRINT(("    Disabling MPS support\n"));
+		return;
+	}
+
+	if (fps_ptr->feature_info[1] & IMPS_FPS_IMCRP_BIT) {
+		str_ptr = "IMCR and PIC";
+	} else {
+		str_ptr = "Virtual Wire";
+	}
+	if (fps_ptr->cth_ptr) {
+		imps_lapic_addr = local_cth_ptr->lapic_addr;
+	} else {
+		imps_lapic_addr = LAPIC_ADDR_DEFAULT;
+	}
+	KERNEL_PRINT(("    APIC config: \"%s mode\"    Local APIC address: 0x%x\n",
+		      str_ptr, imps_lapic_addr));
+	if (imps_lapic_addr != (READ_MSR_LO(0x1b) & 0xFFFFF000)) {
+		KERNEL_PRINT(("Inconsistent Local APIC address, Disabling SMP support\n"));
+		return;
+	}
+	imps_lapic_addr = PHYS_TO_VIRTUAL(imps_lapic_addr);
+
+	/*
+	 *  Setup primary CPU.
+	 */
+	apicid = IMPS_LAPIC_READ(LAPIC_SPIV);
+	IMPS_LAPIC_WRITE(LAPIC_SPIV, apicid|LAPIC_SPIV_ENABLE_APIC);
+	apicid = APIC_ID(IMPS_LAPIC_READ(LAPIC_ID));
+	imps_cpu_apic_map[0] = apicid;
+	imps_apic_cpu_map[apicid] = 0;
+
+	if (fps_ptr->cth_ptr) {
+		char str1[16], str2[16];
+		memcpy(str1, local_cth_ptr->oem_id, 8);
+		str1[8] = 0;
+		memcpy(str2, local_cth_ptr->prod_id, 12);
+		str2[12] = 0;
+		KERNEL_PRINT(("  OEM id: %s  Product id: %s\n", str1, str2));
+		cth_start = ((unsigned) local_cth_ptr) + sizeof(imps_cth);
+		cth_count = local_cth_ptr->entry_count;
+	} else {
+		*((volatile unsigned *) IOAPIC_ADDR_DEFAULT) =  IOAPIC_ID;
+		defconfig.ioapic.id
+			= APIC_ID(*((volatile unsigned *)
+				    (IOAPIC_ADDR_DEFAULT+IOAPIC_RW)));
+		*((volatile unsigned *) IOAPIC_ADDR_DEFAULT) =  IOAPIC_VER;
+		defconfig.ioapic.ver
+			= APIC_VERSION(*((volatile unsigned *)
+					 (IOAPIC_ADDR_DEFAULT+IOAPIC_RW)));
+		defconfig.proc[apicid].flags
+		  = IMPS_FLAG_ENABLED|IMPS_CPUFLAG_BOOT;
+		defconfig.proc[!apicid].flags = IMPS_FLAG_ENABLED;
+		imps_num_cpus = 2;
+		if (fps_ptr->feature_info[0] == 1
+		 || fps_ptr->feature_info[0] == 5) {
+			memcpy(defconfig.bus[0].bus_type, "ISA   ", 6);
+		}
+		if (fps_ptr->feature_info[0] == 4
+		 || fps_ptr->feature_info[0] == 7) {
+			memcpy(defconfig.bus[0].bus_type, "MCA   ", 6);
+		}
+		if (fps_ptr->feature_info[0] > 4) {
+			defconfig.proc[0].apic_ver = 0x10;
+			defconfig.proc[1].apic_ver = 0x10;
+			defconfig.bus[1].type = IMPS_BCT_BUS;
+		}
+		if (fps_ptr->feature_info[0] == 2) {
+			defconfig.intin[2].type = 255;
+			defconfig.intin[13].type = 255;
+		}
+		if (fps_ptr->feature_info[0] == 7) {
+			defconfig.intin[0].type = 255;
+		}
+		cth_start = (unsigned) &defconfig;
+		cth_count = DEF_ENTRIES;
+	}
+	imps_read_config_table(cth_start, cth_count);
+
+	/* %%%%% ESB read extended entries here */
+
+	imps_enabled = 1;
+}
+
+
+/*
+ *  Given a region to check, this actually looks for the "MP Floating
+ *  Pointer Structure".  The return value indicates if the correct
+ *  signature and checksum for a floating pointer structure of the
+ *  appropriate spec revision was found.  If so, then do not search
+ *  further.
+ *
+ *  NOTE:  The memory scan will always be in the bottom 1 MB.
+ *
+ *  This function presumes that "start" will always be aligned to a 16-bit
+ *  boundary.
+ *
+ *  Function finished.
+ */
+
+static int
+imps_scan(unsigned start, unsigned length)
+{
+	IMPS_DEBUG_PRINT(("Scanning from 0x%x for %d bytes\n",
+			  start, length));
+
+	while (length > 0) {
+		imps_fps *fps_ptr = (imps_fps *) PHYS_TO_VIRTUAL(start);
+
+		if (fps_ptr->sig == IMPS_FPS_SIGNATURE
+		 && fps_ptr->length == 1
+		 && (fps_ptr->spec_rev == 1 || fps_ptr->spec_rev == 4)
+		 && !get_checksum(start, 16)) {
+			IMPS_DEBUG_PRINT(("Found MP Floating Structure Pointer at %x\n", start));
+			imps_read_bios(fps_ptr);
+			return 1;
+		}
+
+		length -= 16;
+		start += 16;
+	}
+
+	return 0;
+}
+
+/*
+ *  This is the primary function to "force" SMP support, with
+ *  the assumption that you have consecutively numbered APIC ids.
+ */
+int
+imps_force(int ncpus)
+{
+	int apicid, i;
+	imps_processor p;
+
+	KERNEL_PRINT(("Intel MultiProcessor \"Force\" Support\n"));
+
+	imps_lapic_addr = (READ_MSR_LO(0x1b) & 0xFFFFF000);
+	imps_lapic_addr = PHYS_TO_VIRTUAL(imps_lapic_addr);
+
+	/*
+	 *  Setup primary CPU.
+	 */
+	apicid = IMPS_LAPIC_READ(LAPIC_SPIV);
+	IMPS_LAPIC_WRITE(LAPIC_SPIV, apicid|LAPIC_SPIV_ENABLE_APIC);
+	apicid = APIC_ID(IMPS_LAPIC_READ(LAPIC_ID));
+	imps_cpu_apic_map[0] = apicid;
+	imps_apic_cpu_map[apicid] = 0;
+
+	p.type = 0;
+	p.apic_ver = 0x10;
+	p.signature = p.features = 0;
+
+	for (i = 0; i < ncpus; i++) {
+		if (apicid == i) {
+			p.flags = IMPS_FLAG_ENABLED | IMPS_CPUFLAG_BOOT;
+		} else {
+			p.flags = IMPS_FLAG_ENABLED;
+		}
+		p.apic_id = i;
+		add_processor(&p);
+	}
+
+	return imps_num_cpus;
+}
+
+
+/*
+ *  This is the primary function for probing for MPS compatible hardware
+ *  and BIOS information.  Call this during the early stages of OS startup,
+ *  before memory can be messed up.
+ *
+ *  The probe looks for the "MP Floating Pointer Structure" at locations
+ *  listed at the top of page 4-2 of the spec.
+ *
+ *  Environment requirements from the OS to run:
+ *
+ *   (1) : A non-linear virtual to physical memory mapping is probably OK,
+ *	     as (I think) the structures all fall within page boundaries,
+ *	     but a linear mapping is recommended.  Currently assumes that
+ *	     the mapping will remain identical over time (which should be
+ *	     OK since it only accesses memory which shouldn't be munged
+ *	     by the OS anyway).
+ *   (2) : The OS only consumes memory which the BIOS says is OK to use,
+ *	     and not any of the BIOS standard areas (the areas 0x400 to
+ *	     0x600, the EBDA, 0xE0000 to 0xFFFFF, and unreported physical
+ *	     RAM).  Sometimes a small amount of physical RAM is not
+ *	     reported by the BIOS, to be used to store MPS and other
+ *	     information.
+ *   (3) : It must be possible to read the CMOS.
+ *   (4) : There must be between 512K and 640K of lower memory (this is a
+ *	     sanity check).
+ *
+ *  Function finished.
+ */
+
+int
+imps_probe(void)
+{
+	/*
+	 *  Determine possible address of the EBDA
+	 */
+	unsigned ebda_addr = *((unsigned short *)
+			       PHYS_TO_VIRTUAL(EBDA_SEG_ADDR)) << 4;
+
+	/*
+	 *  Determine amount of installed lower memory (not *available*
+	 *  lower memory).
+	 *
+	 *  NOTE:  This should work reliably as long as we verify the
+	 *         machine is at least a system that could possibly have
+	 *         MPS compatibility to begin with.
+	 */
+	unsigned mem_lower = ((CMOS_READ_BYTE(CMOS_BASE_MEMORY+1) << 8)
+			      | CMOS_READ_BYTE(CMOS_BASE_MEMORY))       << 10;
+
+#ifdef IMPS_DEBUG
+	imps_enabled = 0;
+	imps_num_cpus = 1;
+#endif
+
+	/*
+	 *  Sanity check : if this isn't reasonable, it is almost impossibly
+	 *    unlikely to be an MPS compatible machine, so return failure.
+	 */
+	if (mem_lower < 512*1024 || mem_lower > 640*1024) {
+		return 0;
+	}
+
+	if (ebda_addr > mem_lower - 1024
+	 || ebda_addr + *((unsigned char *) PHYS_TO_VIRTUAL(ebda_addr))
+         * 1024 > mem_lower) {
+		ebda_addr = 0;
+	}
+
+	if (((ebda_addr && imps_scan(ebda_addr, 1024))
+	 || (!ebda_addr && imps_scan(mem_lower - 1024, 1024))
+	 || imps_scan(0xF0000, 0x10000)) && imps_enabled) {
+		return imps_num_cpus;
+	}
+
+	/*
+	 *  If no BIOS info on MPS hardware is found, then return failure.
+	 */
+
+	return 0;
+}
+



--

Generated by Deluxe Loginfo [http://www.codewiz.org/projects/index.html#loginfo] 2.122 by Bernardo Innocenti <bernie at develer.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/vc/attachments/20110714/8bb505a1/attachment-0001.html>


More information about the vc mailing list