<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>change log for rtems (2011-07-14)</title>
</head>
<body text='#000000' bgcolor='#ffffff'>
<a name='cs1'></a>
<table border='0' cellspacing='0' cellpadding='5' width='100%' bgcolor='#eeeeee'>
<tr><td colspan='3' bgcolor='#dddddd'>
 <font color='#bb2222'><strong>jennifer</strong></font>
</td></tr>
<tr><td colspan='3' bgcolor='#dddddd'><pre>2011-07-14 Jennifer Averett <Jennifer.Averett@OARcorp.com>

        * shared/irq/apic.h, shared/smp/README, shared/smp/smp-imps.c,
        shared/smp/smp-imps.h: New files.
</pre></td></tr>
<tr><td width='1%'><a href="http://www.rtems.com/cgi-bin/viewcvs.cgi//rtems/c/src/lib/libbsp/i386/ChangeLog.diff?r1=text&tr1=1.80&r2=text&tr2=1.81&diff_format=h">M</a></td><td width='1%'>1.81</td><td width='100%'>c/src/lib/libbsp/i386/ChangeLog</td></tr>
<tr><td width='1%'><a href="http://www.rtems.com/cgi-bin/viewcvs.cgi//rtems/c/src/lib/libbsp/i386/shared/irq/apic.h?rev=1.1&content-type=text/vnd.viewcvs-markup">A</a></td><td width='1%'><font color="#000088">1.1</font></td><td width='100%'><font color="#000088">c/src/lib/libbsp/i386/shared/irq/apic.h</font></td></tr>
<tr><td width='1%'><a href="http://www.rtems.com/cgi-bin/viewcvs.cgi//rtems/c/src/lib/libbsp/i386/shared/smp/README?rev=1.1&content-type=text/vnd.viewcvs-markup">A</a></td><td width='1%'><font color="#000088">1.1</font></td><td width='100%'><font color="#000088">c/src/lib/libbsp/i386/shared/smp/README</font></td></tr>
<tr><td width='1%'><a href="http://www.rtems.com/cgi-bin/viewcvs.cgi//rtems/c/src/lib/libbsp/i386/shared/smp/smp-imps.h?rev=1.1&content-type=text/vnd.viewcvs-markup">A</a></td><td width='1%'><font color="#000088">1.1</font></td><td width='100%'><font color="#000088">c/src/lib/libbsp/i386/shared/smp/smp-imps.h</font></td></tr>
<tr><td width='1%'><a href="http://www.rtems.com/cgi-bin/viewcvs.cgi//rtems/c/src/lib/libbsp/i386/shared/smp/smp-imps.c?rev=1.1&content-type=text/vnd.viewcvs-markup">A</a></td><td width='1%'><font color="#000088">1.1</font></td><td width='100%'><font color="#000088">c/src/lib/libbsp/i386/shared/smp/smp-imps.c</font></td></tr>
</table>
<pre>
<font color='#006600'>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
</font><font color='#997700'>@@ -1,3 +1,8 @@
</font><font color='#000088'>+2011-07-14    Jennifer Averett <Jennifer.Averett@OARcorp.com>
+
+       * shared/irq/apic.h, shared/smp/README, shared/smp/smp-imps.c,
+       shared/smp/smp-imps.h: New files.
+
</font> 2011-05-25        Ralf Corsépius <ralf.corsepius@rtems.org>
 
        * shared/comm/tty_drv.c, shared/comm/tty_drv.h:

<font color='#006600'>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
</font><font color='#997700'>@@ -0,0 +1,86 @@
</font><font color='#000088'>+/*
+ *  <Insert copyright here : it must be BSD-like so everyone can use it>
+ *
+ *  Author:  Erich Boleyn  <erich@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                  <span style="background-color: #FF0000">       </span>    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            <span style="background-color: #FF0000">       </span>            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 */
+
</font>
<font color='#006600'>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
</font><font color='#997700'>@@ -0,0 +1,14 @@
</font><font color='#000088'>+#
+# $Id$
+#
+
+The following files were developed by  Erich Boleyn  <erich@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
</font>
<font color='#006600'>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
</font><font color='#997700'>@@ -0,0 +1,227 @@
</font><font color='#000088'>+/*
+ *  <Insert copyright here : it must be BSD-like so everyone can use it>
+ *
+ *  Author:  Erich Boleyn  <erich@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 */
+
</font>
<font color='#006600'>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
</font><font color='#997700'>@@ -0,0 +1,649 @@
</font><font color='#000088'>+/*
+ *  <Insert copyright here : it must be BSD-like so anyone can use it>
+ *
+ *  Author:  Erich Boleyn  <erich@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;
+}
+
</font></pre>
<p> </p>

<p>--<br />
<small>Generated by <a href="http://www.codewiz.org/projects/index.html#loginfo">Deluxe Loginfo</a> 2.122 by Bernardo Innocenti <bernie@develer.com></small></p>
</body>
</html>