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 #define MPFPS_SIG "_MP_"
48 #define MPCTH_SIG "PCMP"
50 #define PTOV(pa) ((off_t)(pa))
52 static mpfps_t biosmptable_find_mpfps(void);
53 static mpfps_t biosmptable_search_mpfps(off_t base, int length);
54 static mpcth_t biosmptable_check_mpcth(off_t addr);
56 static int memopen(void);
57 static void memclose(void);
59 int biosmptable_detect(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 warnx("MPTable: Found CPU APIC ID %d %s",
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 warnx("unknown mptable entry type (%d)", *entry_type_p);
112 goto done; /* XXX error return? */
134 pfd = open(_PATH_MEM, O_RDONLY);
136 warn("%s: cannot open", _PATH_MEM);
151 memread(off_t addr, void* entry, size_t size)
153 if ((size_t)pread(pfd, entry, size, addr) != size) {
154 warn("pread (%zu @ 0x%jx)", size, (intmax_t)addr);
162 * Find the MP Floating Pointer Structure. See the MP spec section 4.1.
165 biosmptable_find_mpfps(void)
170 /* EBDA is the 1 KB addressed by the 16 bit pointer at 0x40E. */
171 if (!memread(PTOV(0x40E), &addr, sizeof(addr)))
173 mpfps = biosmptable_search_mpfps(PTOV(addr << 4), 0x400);
177 /* Check the BIOS. */
178 mpfps = biosmptable_search_mpfps(PTOV(0xf0000), 0x10000);
186 biosmptable_search_mpfps(off_t base, int length)
192 mpfps = malloc(sizeof(*mpfps));
194 warnx("unable to malloc space for MP Floating Pointer Structure");
197 /* search on 16-byte boundaries */
198 for (ofs = 0; ofs < length; ofs += 16) {
199 if (!memread(base + ofs, mpfps, sizeof(*mpfps)))
202 /* compare signature, validate checksum */
203 if (!strncmp(mpfps->signature, MPFPS_SIG, strlen(MPFPS_SIG))) {
204 cp = (u_int8_t *)mpfps;
206 /* mpfps is 16 bytes, or one "paragraph" */
207 if (mpfps->length != 1) {
208 warnx("bad mpfps length (%d)", mpfps->length);
211 for (idx = 0; idx < mpfps->length * 16; idx++)
214 warnx("bad mpfps checksum (%d)\n", sum);
225 biosmptable_check_mpcth(off_t addr)
229 int idx, table_length;
231 /* mpcth must be in the first 1MB */
232 if ((u_int32_t)addr >= 1024 * 1024) {
233 warnx("bad mpcth address (0x%jx)\n", (intmax_t)addr);
237 mpcth = malloc(sizeof(*mpcth));
239 warnx("unable to malloc space for MP Configuration Table Header");
242 if (!memread(addr, mpcth, sizeof(*mpcth)))
244 /* Compare signature and validate checksum. */
245 if (strncmp(mpcth->signature, MPCTH_SIG, strlen(MPCTH_SIG)) != 0) {
246 warnx("bad mpcth signature");
249 table_length = mpcth->base_table_length;
250 mpcth = realloc(mpcth, table_length);
252 warnx("unable to realloc space for mpcth (len %u)", table_length);
255 if (!memread(addr, mpcth, table_length))
257 cp = (u_int8_t *)mpcth;
259 for (idx = 0; idx < mpcth->base_table_length; idx++)
262 warnx("bad mpcth checksum (%d)", sum);