]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sysinstall/biosmptable.c
This commit was generated by cvs2svn to compensate for changes in r167617,
[FreeBSD/FreeBSD.git] / usr.sbin / sysinstall / biosmptable.c
1 /*-
2  * Copyright (c) 2005 Sandvine Incorporated.  All righs reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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
23  * SUCH DAMAGE.
24  *
25  * Author: Ed Maste <emaste@phaedrus.sandvine.ca>
26  */
27
28 /*
29  * This module detects Intel Multiprocessor spec info (mptable) and returns
30  * the number of cpu's identified.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/types.h>
37 #include <machine/mptable.h>
38
39 #include <fcntl.h>
40 #include <inttypes.h>
41 #include <paths.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #include "sysinstall.h"
47
48 #define MPFPS_SIG "_MP_"
49 #define MPCTH_SIG "PCMP"
50
51 #define PTOV(pa)        ((off_t)(pa))
52
53 static mpfps_t biosmptable_find_mpfps(void);
54 static mpfps_t biosmptable_search_mpfps(off_t base, int length);
55 static mpcth_t biosmptable_check_mpcth(off_t addr);
56
57 static int memopen(void);
58 static void memclose(void);
59
60 int
61 biosmptable_detect(void)
62 {
63     mpfps_t mpfps;
64     mpcth_t mpcth;
65     char *entry_type_p;
66     proc_entry_ptr proc;
67     int ncpu, i;
68
69     if (!memopen())
70         return -1;              /* XXX 0? */
71     /* locate and validate the mpfps */
72     mpfps = biosmptable_find_mpfps();
73     mpcth = NULL;
74     if (mpfps == NULL) {
75         ncpu = 0;
76     } else if (mpfps->config_type != 0) {
77         /* 
78          * If thie config_type is nonzero then this is a default configuration
79          * from Chapter 5 in the MP spec.  Report 2 cpus and 1 I/O APIC.
80          */
81         ncpu = 2;
82     } else {
83         ncpu = 0;
84         mpcth = biosmptable_check_mpcth(PTOV(mpfps->pap));
85         if (mpcth != NULL) {
86             entry_type_p = (char *)(mpcth + 1);
87             for (i = 0; i < mpcth->entry_count; i++) {
88                 switch (*entry_type_p) {
89                 case 0:
90                     entry_type_p += sizeof(struct PROCENTRY);
91                     proc = (proc_entry_ptr) entry_type_p;
92                     msgDebug("MPTable: Found CPU APIC ID %d %s\n",
93                         proc->apic_id,
94                         proc->cpu_flags & PROCENTRY_FLAG_EN ?
95                                 "enabled" : "disabled");
96                     if (proc->cpu_flags & PROCENTRY_FLAG_EN)
97                         ncpu++;
98                     break;
99                 case 1:
100                     entry_type_p += sizeof(struct BUSENTRY);
101                     break;
102                 case 2:
103                     entry_type_p += sizeof(struct IOAPICENTRY);
104                     break;
105                 case 3:
106                 case 4:
107                     entry_type_p += sizeof(struct INTENTRY);
108                     break;
109                 default:
110                     msgDebug("%s: unknown mptable entry type (%d)\n",
111                         __func__, *entry_type_p);
112                     goto done;          /* XXX error return? */
113                 }
114             }
115         done:
116             ;
117         }
118     }
119     memclose();
120     if (mpcth != NULL)
121         free(mpcth);
122     if (mpfps != NULL)
123         free(mpfps);
124
125     return ncpu;
126 }
127
128 static int pfd = -1;
129
130 static int
131 memopen(void)
132 {
133     if (pfd < 0) {
134         pfd = open(_PATH_MEM, O_RDONLY);
135         if (pfd < 0)
136                 warn("%s: cannot open", _PATH_MEM);
137     }
138     return pfd >= 0;
139 }
140
141 static void
142 memclose(void)
143 {
144     if (pfd >= 0) {
145         close(pfd);
146         pfd = -1;
147     }
148 }
149
150 static int
151 memread(off_t addr, void* entry, size_t size)
152 {
153     if ((size_t)pread(pfd, entry, size, addr) != size) {
154         warn("pread (%lu @ 0x%lx)", size, addr);
155         return 0;
156     }
157     return 1;
158 }
159
160
161 /*
162  * Find the MP Floating Pointer Structure.  See the MP spec section 4.1.
163  */
164 static mpfps_t
165 biosmptable_find_mpfps(void)
166 {
167     mpfps_t mpfps;
168     uint16_t addr;
169
170     /* EBDA is the 1 KB addressed by the 16 bit pointer at 0x40E. */
171     if (!memread(PTOV(0x40E), &addr, sizeof(addr)))
172         return (NULL);
173     mpfps = biosmptable_search_mpfps(PTOV(addr << 4), 0x400);
174     if (mpfps != NULL)
175         return (mpfps);
176
177     /* Check the BIOS. */
178     mpfps = biosmptable_search_mpfps(PTOV(0xf0000), 0x10000);
179     if (mpfps != NULL)
180         return (mpfps);
181
182     return (NULL);
183 }
184
185 static mpfps_t
186 biosmptable_search_mpfps(off_t base, int length)
187 {
188     mpfps_t mpfps;
189     u_int8_t *cp, sum;
190     int ofs, idx;
191
192     mpfps = malloc(sizeof(*mpfps));
193     if (mpfps == NULL) {
194         msgDebug("%s: unable to malloc space for "
195             "MP Floating Pointer Structure\n", __func__);
196         return (NULL);
197     }
198     /* search on 16-byte boundaries */
199     for (ofs = 0; ofs < length; ofs += 16) {
200         if (!memread(base + ofs, mpfps, sizeof(*mpfps)))
201             break;
202
203         /* compare signature, validate checksum */
204         if (!strncmp(mpfps->signature, MPFPS_SIG, strlen(MPFPS_SIG))) {
205             cp = (u_int8_t *)mpfps;
206             sum = 0;
207             /* mpfps is 16 bytes, or one "paragraph" */
208             if (mpfps->length != 1) {
209                 msgDebug("%s: bad mpfps length (%d)\n",
210                     __func__, mpfps->length);
211                 continue;
212             }
213             for (idx = 0; idx < mpfps->length * 16; idx++)
214                 sum += *(cp + idx);
215             if (sum != 0) {
216                 msgDebug("%s: bad mpfps checksum (%d)\n", __func__, sum);
217                 continue;
218             }
219             return (mpfps);
220         }
221     }
222     free(mpfps);
223     return (NULL);
224 }
225
226 static mpcth_t
227 biosmptable_check_mpcth(off_t addr)
228 {
229     mpcth_t mpcth;
230     u_int8_t *cp, sum;
231     int idx, table_length;
232
233     /* mpcth must be in the first 1MB */
234     if ((u_int32_t)addr >= 1024 * 1024) {
235         msgDebug("%s: bad mpcth address (0x%lx)\n", __func__, addr);
236         return (NULL);
237     }
238
239     mpcth = malloc(sizeof(*mpcth));
240     if (mpcth == NULL) {
241         msgDebug("%s: unable to malloc space for "
242             "MP Configuration Table Header\n", __func__);
243         return (NULL);
244     }
245     if (!memread(addr, mpcth, sizeof(*mpcth)))
246         goto bad;
247     /* Compare signature and validate checksum. */
248     if (strncmp(mpcth->signature, MPCTH_SIG, strlen(MPCTH_SIG)) != 0) {
249         msgDebug("%s: bad mpcth signature\n", __func__);
250         goto bad;
251     }
252     table_length = mpcth->base_table_length;
253     mpcth = realloc(mpcth, table_length);
254     if (mpcth == NULL) {
255         msgDebug("%s: unable to realloc space for mpcth (len %u)\n",
256             __func__, table_length);
257         return  (NULL);
258     }
259     if (!memread(addr, mpcth, table_length))
260         goto bad;
261     cp = (u_int8_t *)mpcth;
262     sum = 0;
263     for (idx = 0; idx < mpcth->base_table_length; idx++)
264         sum += *(cp + idx);
265     if (sum != 0) {
266         msgDebug("%s: bad mpcth checksum (%d)\n", __func__, sum);
267         goto bad;
268     }
269
270     return mpcth;
271 bad:
272     free(mpcth);
273     return (NULL);
274 }