]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/bhyve/mptbl.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / usr.sbin / bhyve / mptbl.c
1 /*-
2  * Copyright (c) 2012 NetApp, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <x86/mptable.h>
35
36 #include <stdio.h>
37 #include <string.h>
38
39 #include "bhyverun.h"
40 #include "mptbl.h"
41
42 #define MPTABLE_BASE            0xF0000
43
44 /* floating pointer length + maximum length of configuration table */
45 #define MPTABLE_MAX_LENGTH      (65536 + 16)
46
47 #define LAPIC_PADDR             0xFEE00000
48 #define LAPIC_VERSION           16
49
50 #define IOAPIC_PADDR            0xFEC00000
51 #define IOAPIC_VERSION          0x11
52
53 #define MP_SPECREV              4
54 #define MPFP_SIG                "_MP_"
55
56 /* Configuration header defines */
57 #define MPCH_SIG                "PCMP"
58 #define MPCH_OEMID              "BHyVe   "
59 #define MPCH_OEMID_LEN          8
60 #define MPCH_PRODID             "Hypervisor  "
61 #define MPCH_PRODID_LEN         12
62
63 /* Processor entry defines */
64 #define MPEP_SIG_FAMILY         6       /* XXX bhyve should supply this */
65 #define MPEP_SIG_MODEL          26
66 #define MPEP_SIG_STEPPING       5
67 #define MPEP_SIG                \
68         ((MPEP_SIG_FAMILY << 8) | \
69          (MPEP_SIG_MODEL << 4)  | \
70          (MPEP_SIG_STEPPING))
71
72 #define MPEP_FEATURES           (0xBFEBFBFF) /* XXX Intel i7 */
73
74 /* Define processor entry struct since <x86/mptable.h> gets it wrong */
75 typedef struct BPROCENTRY {
76         u_char          type;
77         u_char          apic_id;
78         u_char          apic_version;
79         u_char          cpu_flags;
80         uint32_t        cpu_signature;
81         uint32_t        feature_flags;
82         uint32_t        reserved1;
83         uint32_t        reserved2;
84 }      *bproc_entry_ptr;
85 CTASSERT(sizeof(struct BPROCENTRY) == 20);
86
87 /* Bus entry defines */
88 #define MPE_NUM_BUSES           2
89 #define MPE_BUSNAME_LEN         6
90 #define MPE_BUSNAME_ISA         "ISA   "
91 #define MPE_BUSNAME_PCI         "PCI   "
92
93 static void *oem_tbl_start;
94 static int oem_tbl_size;
95
96 static uint8_t
97 mpt_compute_checksum(void *base, size_t len)
98 {
99         uint8_t *bytes;
100         uint8_t sum;
101
102         for(bytes = base, sum = 0; len > 0; len--) {
103                 sum += *bytes++;
104         }
105
106         return (256 - sum);
107 }
108
109 static void
110 mpt_build_mpfp(mpfps_t mpfp, vm_paddr_t gpa)
111 {
112
113         memset(mpfp, 0, sizeof(*mpfp));
114         memcpy(mpfp->signature, MPFP_SIG, 4);
115         mpfp->pap = gpa + sizeof(*mpfp);
116         mpfp->length = 1;
117         mpfp->spec_rev = MP_SPECREV;
118         mpfp->checksum = mpt_compute_checksum(mpfp, sizeof(*mpfp));
119 }
120
121 static void
122 mpt_build_mpch(mpcth_t mpch)
123 {
124
125         memset(mpch, 0, sizeof(*mpch));
126         memcpy(mpch->signature, MPCH_SIG, 4);
127         mpch->spec_rev = MP_SPECREV;
128         memcpy(mpch->oem_id, MPCH_OEMID, MPCH_OEMID_LEN);
129         memcpy(mpch->product_id, MPCH_PRODID, MPCH_PRODID_LEN);
130         mpch->apic_address = LAPIC_PADDR;
131 }
132
133 static void
134 mpt_build_proc_entries(bproc_entry_ptr mpep, int ncpu)
135 {
136         int i;
137
138         for (i = 0; i < ncpu; i++) {
139                 memset(mpep, 0, sizeof(*mpep));
140                 mpep->type = MPCT_ENTRY_PROCESSOR;
141                 mpep->apic_id = i; // XXX
142                 mpep->apic_version = LAPIC_VERSION;
143                 mpep->cpu_flags = PROCENTRY_FLAG_EN;
144                 if (i == 0)
145                         mpep->cpu_flags |= PROCENTRY_FLAG_BP;
146                 mpep->cpu_signature = MPEP_SIG;
147                 mpep->feature_flags = MPEP_FEATURES;
148                 mpep++;
149         }
150 }
151
152 static void
153 mpt_build_bus_entries(bus_entry_ptr mpeb)
154 {
155
156         memset(mpeb, 0, sizeof(*mpeb));
157         mpeb->type = MPCT_ENTRY_BUS;
158         mpeb->bus_id = ISA;
159         memcpy(mpeb->bus_type, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN);
160         mpeb++;
161
162         memset(mpeb, 0, sizeof(*mpeb));
163         mpeb->type = MPCT_ENTRY_BUS;
164         mpeb->bus_id = PCI;
165         memcpy(mpeb->bus_type, MPE_BUSNAME_PCI, MPE_BUSNAME_LEN);
166 }
167
168 static void
169 mpt_build_ioapic_entries(io_apic_entry_ptr mpei, int id)
170 {
171
172         memset(mpei, 0, sizeof(*mpei));
173         mpei->type = MPCT_ENTRY_IOAPIC;
174         mpei->apic_id = id;
175         mpei->apic_version = IOAPIC_VERSION;
176         mpei->apic_flags = IOAPICENTRY_FLAG_EN;
177         mpei->apic_address = IOAPIC_PADDR;
178 }
179
180 #ifdef notyet
181 static void
182 mpt_build_ioint_entries(struct mpe_ioint *mpeii, int num_pins, int id)
183 {
184         int pin;
185
186         /*
187          * The following config is taken from kernel mptable.c
188          * mptable_parse_default_config_ints(...), for now 
189          * just use the default config, tweek later if needed.
190          */
191
192
193         /* Run through all 16 pins. */
194         for (pin = 0; pin < num_pins; pin++) {
195                 memset(mpeii, 0, sizeof(*mpeii));
196                 mpeii->entry_type = MP_ENTRY_IOINT;
197                 mpeii->src_bus_id = MPE_BUSID_ISA;
198                 mpeii->dst_apic_id = id;
199
200                 /*
201                  * All default configs route IRQs from bus 0 to the first 16
202                  * pins of the first I/O APIC with an APIC ID of 2.
203                  */
204                 mpeii->dst_apic_intin = pin;
205                 switch (pin) {
206                 case 0:
207                         /* Pin 0 is an ExtINT pin. */
208                         mpeii->intr_type = MPEII_INTR_EXTINT;
209                         break;
210                 case 2:
211                         /* IRQ 0 is routed to pin 2. */
212                         mpeii->intr_type = MPEII_INTR_INT;
213                         mpeii->src_bus_irq = 0;
214                         break;
215                 case 5:
216                 case 10:
217                 case 11:
218                         /*
219                          * PCI Irqs set to level triggered.
220                          */
221                         mpeii->intr_flags = MPEII_FLAGS_TRIGMODE_LEVEL;
222                         mpeii->src_bus_id = MPE_BUSID_PCI;
223                 default:
224                         /* All other pins are identity mapped. */
225                         mpeii->intr_type = MPEII_INTR_INT;
226                         mpeii->src_bus_irq = pin;
227                         break;
228                 }
229                 mpeii++;
230         }
231
232 }
233
234 #define COPYSTR(dest, src, bytes)               \
235         memcpy(dest, src, bytes);               \
236         str[bytes] = 0;
237
238 static void
239 mptable_dump(struct mp_floating_pointer *mpfp, struct mp_config_hdr *mpch)
240 {
241         static char      str[16];
242         int              i;
243         char            *cur;
244
245         union mpe {
246                 struct mpe_proc         *proc;
247                 struct mpe_bus          *bus;
248                 struct mpe_ioapic       *ioapic;
249                 struct mpe_ioint        *ioint;
250                 struct mpe_lint         *lnit;
251                 char                    *p;
252         };
253
254         union mpe mpe;
255
256         printf(" MP Floating Pointer :\n");
257         COPYSTR(str, mpfp->signature, 4);
258         printf("\tsignature:\t%s\n", str);
259         printf("\tmpch paddr:\t%x\n", mpfp->mptable_paddr);
260         printf("\tlength:\t%x\n", mpfp->length);
261         printf("\tspecrec:\t%x\n", mpfp->specrev);
262         printf("\tchecksum:\t%x\n", mpfp->checksum);
263         printf("\tfeature1:\t%x\n", mpfp->feature1);
264         printf("\tfeature2:\t%x\n", mpfp->feature2);
265         printf("\tfeature3:\t%x\n", mpfp->feature3);
266         printf("\tfeature4:\t%x\n", mpfp->feature4);
267
268         printf(" MP Configuration Header :\n");
269         COPYSTR(str, mpch->signature, 4);
270         printf("    signature:          %s\n", str);
271         printf("    length:             %x\n", mpch->length);
272         printf("    specrec:            %x\n", mpch->specrev);
273         printf("    checksum:           %x\n", mpch->checksum);
274         COPYSTR(str, mpch->oemid, MPCH_OEMID_LEN);
275         printf("    oemid:              %s\n", str);
276         COPYSTR(str, mpch->prodid, MPCH_PRODID_LEN);
277         printf("    prodid:             %s\n", str);
278         printf("    oem_ptr:            %x\n", mpch->oem_ptr);
279         printf("    oem_sz:             %x\n", mpch->oem_sz);
280         printf("    nr_entries:         %x\n", mpch->nr_entries);
281         printf("    apic paddr:         %x\n", mpch->lapic_paddr);
282         printf("    ext_length:         %x\n", mpch->ext_length);
283         printf("    ext_checksum:       %x\n", mpch->ext_checksum);
284
285         cur = (char *)mpch + sizeof(*mpch);
286         for (i = 0; i < mpch->nr_entries; i++) {
287                 mpe.p = cur;
288                 switch(*mpe.p) {                
289                         case MP_ENTRY_PROC:
290                                 printf(" MP Processor Entry :\n");
291                                 printf("        lapic_id:       %x\n", mpe.proc->lapic_id);
292                                 printf("        lapic_version:  %x\n", mpe.proc->lapic_version);
293                                 printf("        proc_flags:     %x\n", mpe.proc->proc_flags);
294                                 printf("        proc_signature: %x\n", mpe.proc->proc_signature);
295                                 printf("        feature_flags:  %x\n", mpe.proc->feature_flags);
296                                 cur += sizeof(struct mpe_proc);
297                                 break;
298                         case MP_ENTRY_BUS:
299                                 printf(" MP Bus Entry :\n");
300                                 printf("        busid:          %x\n", mpe.bus->busid);
301                                 COPYSTR(str, mpe.bus->busname, MPE_BUSNAME_LEN);
302                                 printf("        busname:        %s\n", str);
303                                 cur += sizeof(struct mpe_bus);
304                                 break;
305                         case MP_ENTRY_IOAPIC:
306                                 printf(" MP IOAPIC Entry :\n");
307                                 printf("        ioapi_id:               %x\n", mpe.ioapic->ioapic_id);
308                                 printf("        ioapi_version:          %x\n", mpe.ioapic->ioapic_version);
309                                 printf("        ioapi_flags:            %x\n", mpe.ioapic->ioapic_flags);
310                                 printf("        ioapi_paddr:            %x\n", mpe.ioapic->ioapic_paddr);
311                                 cur += sizeof(struct mpe_ioapic);
312                                 break;
313                         case MP_ENTRY_IOINT:
314                                 printf(" MP IO Interrupt Entry :\n");
315                                 printf("        intr_type:              %x\n", mpe.ioint->intr_type);
316                                 printf("        intr_flags:             %x\n", mpe.ioint->intr_flags);
317                                 printf("        src_bus_id:             %x\n", mpe.ioint->src_bus_id);
318                                 printf("        src_bus_irq:            %x\n", mpe.ioint->src_bus_irq);
319                                 printf("        dst_apic_id:            %x\n", mpe.ioint->dst_apic_id);
320                                 printf("        dst_apic_intin:         %x\n", mpe.ioint->dst_apic_intin);
321                                 cur += sizeof(struct mpe_ioint);
322                                 break;
323                         case MP_ENTRY_LINT:
324                                 printf(" MP Local Interrupt Entry :\n");
325                                 cur += sizeof(struct mpe_lint);
326                                 break;
327                 }
328
329         }
330 }
331 #endif
332
333 void
334 mptable_add_oemtbl(void *tbl, int tblsz)
335 {
336
337         oem_tbl_start = tbl;
338         oem_tbl_size = tblsz;
339 }
340
341 int
342 mptable_build(struct vmctx *ctx, int ncpu, int ioapic)
343 {
344         mpcth_t                 mpch;
345         bus_entry_ptr           mpeb;
346         io_apic_entry_ptr       mpei;
347         bproc_entry_ptr         mpep;
348         mpfps_t                 mpfp;
349         char                    *curraddr;
350         char                    *startaddr;
351
352         startaddr = paddr_guest2host(ctx, MPTABLE_BASE, MPTABLE_MAX_LENGTH);
353         if (startaddr == NULL) {
354                 printf("mptable requires mapped mem\n");
355                 return (ENOMEM);
356         }
357
358         curraddr = startaddr;
359         mpfp = (mpfps_t)curraddr;
360         mpt_build_mpfp(mpfp, MPTABLE_BASE);
361         curraddr += sizeof(*mpfp);
362
363         mpch = (mpcth_t)curraddr;
364         mpt_build_mpch(mpch);
365         curraddr += sizeof(*mpch);
366
367         mpep = (bproc_entry_ptr)curraddr;
368         mpt_build_proc_entries(mpep, ncpu);
369         curraddr += sizeof(*mpep) * ncpu;
370         mpch->entry_count += ncpu;
371
372         mpeb = (bus_entry_ptr) curraddr;
373         mpt_build_bus_entries(mpeb);
374         curraddr += sizeof(*mpeb) * MPE_NUM_BUSES;
375         mpch->entry_count += MPE_NUM_BUSES;
376
377         if (ioapic) {
378                 mpei = (io_apic_entry_ptr)curraddr;
379                 mpt_build_ioapic_entries(mpei, ncpu + 1);
380                 curraddr += sizeof(*mpei);
381                 mpch->entry_count++;
382         }
383
384 #ifdef notyet
385         mpt_build_ioint_entries((struct mpe_ioint*)curraddr, MPEII_MAX_IRQ,
386                                 ncpu + 1);
387         curraddr += sizeof(struct mpe_ioint) * MPEII_MAX_IRQ;
388         mpch->entry_count += MPEII_MAX_IRQ;
389 #endif
390
391         if (oem_tbl_start) {
392                 mpch->oem_table_pointer = curraddr - startaddr + MPTABLE_BASE;
393                 mpch->oem_table_size = oem_tbl_size;
394                 memcpy(curraddr, oem_tbl_start, oem_tbl_size);
395         }
396
397         mpch->base_table_length = curraddr - (char *)mpch;
398         mpch->checksum = mpt_compute_checksum(mpch, mpch->base_table_length);
399
400         return (0);
401 }