2 * Copyright (c) 2005 Sandvine Incorporated. All righs reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * Author: Ed Maste <emaste@phaedrus.sandvine.ca>
29 * This module detects Intel Multiprocessor spec info (mptable) and returns
30 * the number of cpu's identified.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/types.h>
37 #include <machine/mptable.h>
47 #include "sysinstall.h"
49 #define MPFPS_SIG "_MP_"
50 #define MPCTH_SIG "PCMP"
52 #define PTOV(pa) ((off_t)(pa))
54 static mpfps_t biosmptable_find_mpfps(void);
55 static mpfps_t biosmptable_search_mpfps(off_t base, int length);
56 static mpcth_t biosmptable_check_mpcth(off_t addr);
58 static int memopen(void);
59 static void memclose(void);
62 biosmptable_detect(void)
71 return -1; /* XXX 0? */
72 /* locate and validate the mpfps */
73 mpfps = biosmptable_find_mpfps();
77 } else if (mpfps->config_type != 0) {
79 * If thie config_type is nonzero then this is a default configuration
80 * from Chapter 5 in the MP spec. Report 2 cpus and 1 I/O APIC.
85 mpcth = biosmptable_check_mpcth(PTOV(mpfps->pap));
87 entry_type_p = (char *)(mpcth + 1);
88 for (i = 0; i < mpcth->entry_count; i++) {
89 switch (*entry_type_p) {
91 entry_type_p += sizeof(struct PROCENTRY);
92 proc = (proc_entry_ptr) entry_type_p;
93 msgDebug("MPTable: Found CPU APIC ID %d %s\n",
95 proc->cpu_flags & PROCENTRY_FLAG_EN ?
96 "enabled" : "disabled");
97 if (proc->cpu_flags & PROCENTRY_FLAG_EN)
101 entry_type_p += sizeof(struct BUSENTRY);
104 entry_type_p += sizeof(struct IOAPICENTRY);
108 entry_type_p += sizeof(struct INTENTRY);
111 msgDebug("%s: unknown mptable entry type (%d)\n",
112 __func__, *entry_type_p);
113 goto done; /* XXX error return? */
135 pfd = open(_PATH_MEM, O_RDONLY);
137 warn("%s: cannot open", _PATH_MEM);
152 memread(off_t addr, void* entry, size_t size)
154 if ((size_t)pread(pfd, entry, size, addr) != size) {
155 warn("pread (%zu @ 0x%llx)", size, addr);
163 * Find the MP Floating Pointer Structure. See the MP spec section 4.1.
166 biosmptable_find_mpfps(void)
171 /* EBDA is the 1 KB addressed by the 16 bit pointer at 0x40E. */
172 if (!memread(PTOV(0x40E), &addr, sizeof(addr)))
174 mpfps = biosmptable_search_mpfps(PTOV(addr << 4), 0x400);
178 /* Check the BIOS. */
179 mpfps = biosmptable_search_mpfps(PTOV(0xf0000), 0x10000);
187 biosmptable_search_mpfps(off_t base, int length)
193 mpfps = malloc(sizeof(*mpfps));
195 msgDebug("%s: unable to malloc space for "
196 "MP Floating Pointer Structure\n", __func__);
199 /* search on 16-byte boundaries */
200 for (ofs = 0; ofs < length; ofs += 16) {
201 if (!memread(base + ofs, mpfps, sizeof(*mpfps)))
204 /* compare signature, validate checksum */
205 if (!strncmp(mpfps->signature, MPFPS_SIG, strlen(MPFPS_SIG))) {
206 cp = (u_int8_t *)mpfps;
208 /* mpfps is 16 bytes, or one "paragraph" */
209 if (mpfps->length != 1) {
210 msgDebug("%s: bad mpfps length (%d)\n",
211 __func__, mpfps->length);
214 for (idx = 0; idx < mpfps->length * 16; idx++)
217 msgDebug("%s: bad mpfps checksum (%d)\n", __func__, sum);
228 biosmptable_check_mpcth(off_t addr)
232 int idx, table_length;
234 /* mpcth must be in the first 1MB */
235 if ((u_int32_t)addr >= 1024 * 1024) {
236 msgDebug("%s: bad mpcth address (0x%llx)\n", __func__, addr);
240 mpcth = malloc(sizeof(*mpcth));
242 msgDebug("%s: unable to malloc space for "
243 "MP Configuration Table Header\n", __func__);
246 if (!memread(addr, mpcth, sizeof(*mpcth)))
248 /* Compare signature and validate checksum. */
249 if (strncmp(mpcth->signature, MPCTH_SIG, strlen(MPCTH_SIG)) != 0) {
250 msgDebug("%s: bad mpcth signature\n", __func__);
253 table_length = mpcth->base_table_length;
254 mpcth = realloc(mpcth, table_length);
256 msgDebug("%s: unable to realloc space for mpcth (len %u)\n",
257 __func__, table_length);
260 if (!memread(addr, mpcth, table_length))
262 cp = (u_int8_t *)mpcth;
264 for (idx = 0; idx < mpcth->base_table_length; idx++)
267 msgDebug("%s: bad mpcth checksum (%d)\n", __func__, sum);