Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bhyve/acpi.c
105240 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2012 NetApp, Inc.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
/*
30
* bhyve ACPI table generator.
31
*
32
* Create the minimal set of ACPI tables required to boot FreeBSD (and
33
* hopefully other o/s's).
34
*
35
* The tables are placed in the guest's ROM area just below 1MB physical,
36
* above the MPTable.
37
*/
38
39
#include <sys/param.h>
40
#include <sys/cpuset.h>
41
#include <sys/domainset.h>
42
#include <sys/endian.h>
43
#include <sys/errno.h>
44
#include <sys/stat.h>
45
#include <sys/tree.h>
46
47
#include <err.h>
48
#include <paths.h>
49
#include <stdarg.h>
50
#include <stddef.h>
51
#include <stdio.h>
52
#include <stdlib.h>
53
#include <string.h>
54
#include <unistd.h>
55
56
#include <dev/vmm/vmm_mem.h>
57
#include <machine/vmm.h>
58
#include <machine/vmm_dev.h>
59
#include <vmmapi.h>
60
61
#include "bhyverun.h"
62
#include "acpi.h"
63
#include "basl.h"
64
#include "pci_emul.h"
65
#include "vmgenc.h"
66
67
#define BHYVE_ASL_TEMPLATE "bhyve.XXXXXXX"
68
#define BHYVE_ASL_SUFFIX ".aml"
69
#define BHYVE_ASL_COMPILER "/usr/sbin/iasl"
70
71
#define BHYVE_ADDRESS_IOAPIC 0xFEC00000
72
#define BHYVE_ADDRESS_HPET 0xFED00000
73
#define BHYVE_ADDRESS_LAPIC 0xFEE00000
74
75
static int basl_keep_temps;
76
static int basl_verbose_iasl;
77
static int basl_ncpu;
78
79
/*
80
* Contains the full pathname of the template to be passed
81
* to mkstemp/mktemps(3)
82
*/
83
static char basl_template[MAXPATHLEN];
84
static char basl_stemplate[MAXPATHLEN];
85
86
/*
87
* SRAT vCPU affinity info.
88
*/
89
struct acpi_vcpu_affinity_entry {
90
RB_ENTRY(acpi_vcpu_affinity_entry) entry;
91
int vcpuid;
92
int domain;
93
};
94
95
static int vcpu_affinity_cmp(struct acpi_vcpu_affinity_entry *const a1,
96
struct acpi_vcpu_affinity_entry *const a2);
97
static RB_HEAD(vcpu_affinities,
98
acpi_vcpu_affinity_entry) aff_head = RB_INITIALIZER(&aff_head);
99
RB_GENERATE_STATIC(vcpu_affinities, acpi_vcpu_affinity_entry, entry,
100
vcpu_affinity_cmp);
101
102
/*
103
* State for dsdt_line(), dsdt_indent(), and dsdt_unindent().
104
*/
105
static FILE *dsdt_fp;
106
static int dsdt_indent_level;
107
static int dsdt_error;
108
109
struct basl_fio {
110
int fd;
111
FILE *fp;
112
char f_name[MAXPATHLEN];
113
};
114
115
#define EFPRINTF(...) \
116
if (fprintf(__VA_ARGS__) < 0) goto err_exit
117
118
#define EFFLUSH(x) \
119
if (fflush(x) != 0) goto err_exit
120
121
/*
122
* A list for additional ACPI devices like a TPM.
123
*/
124
struct acpi_device_list_entry {
125
SLIST_ENTRY(acpi_device_list_entry) chain;
126
const struct acpi_device *dev;
127
};
128
static SLIST_HEAD(acpi_device_list,
129
acpi_device_list_entry) acpi_devices = SLIST_HEAD_INITIALIZER(acpi_devices);
130
131
int
132
acpi_tables_add_device(const struct acpi_device *const dev)
133
{
134
struct acpi_device_list_entry *const entry = calloc(1, sizeof(*entry));
135
if (entry == NULL) {
136
return (ENOMEM);
137
}
138
139
entry->dev = dev;
140
SLIST_INSERT_HEAD(&acpi_devices, entry, chain);
141
142
return (0);
143
}
144
145
static int
146
vcpu_affinity_cmp(struct acpi_vcpu_affinity_entry *a1,
147
struct acpi_vcpu_affinity_entry *a2)
148
{
149
return (a1->vcpuid < a2->vcpuid ? -1 : a1->vcpuid > a2->vcpuid);
150
}
151
152
int
153
acpi_add_vcpu_affinity(int vcpuid, int domain)
154
{
155
struct acpi_vcpu_affinity_entry *entry = calloc(1, sizeof(*entry));
156
if (entry == NULL) {
157
return (ENOMEM);
158
}
159
160
entry->vcpuid = vcpuid;
161
entry->domain = domain;
162
if (RB_INSERT(vcpu_affinities, &aff_head, entry) != NULL) {
163
free(entry);
164
return (EEXIST);
165
}
166
167
return (0);
168
}
169
170
/*
171
* Helper routines for writing to the DSDT from other modules.
172
*/
173
void
174
dsdt_line(const char *fmt, ...)
175
{
176
va_list ap;
177
178
if (dsdt_error != 0)
179
return;
180
181
if (strcmp(fmt, "") != 0) {
182
if (dsdt_indent_level != 0)
183
EFPRINTF(dsdt_fp, "%*c", dsdt_indent_level * 2, ' ');
184
va_start(ap, fmt);
185
if (vfprintf(dsdt_fp, fmt, ap) < 0) {
186
va_end(ap);
187
goto err_exit;
188
}
189
va_end(ap);
190
}
191
EFPRINTF(dsdt_fp, "\n");
192
return;
193
194
err_exit:
195
dsdt_error = errno;
196
}
197
198
void
199
dsdt_indent(int levels)
200
{
201
202
dsdt_indent_level += levels;
203
assert(dsdt_indent_level >= 0);
204
}
205
206
void
207
dsdt_unindent(int levels)
208
{
209
210
assert(dsdt_indent_level >= levels);
211
dsdt_indent_level -= levels;
212
}
213
214
void
215
dsdt_fixed_ioport(uint16_t iobase, uint16_t length)
216
{
217
218
dsdt_line("IO (Decode16,");
219
dsdt_line(" 0x%04X, // Range Minimum", iobase);
220
dsdt_line(" 0x%04X, // Range Maximum", iobase);
221
dsdt_line(" 0x01, // Alignment");
222
dsdt_line(" 0x%02X, // Length", length);
223
dsdt_line(" )");
224
}
225
226
void
227
dsdt_fixed_irq(uint8_t irq)
228
{
229
230
dsdt_line("IRQNoFlags ()");
231
dsdt_line(" {%d}", irq);
232
}
233
234
void
235
dsdt_fixed_mem32(uint32_t base, uint32_t length)
236
{
237
238
dsdt_line("Memory32Fixed (ReadWrite,");
239
dsdt_line(" 0x%08X, // Address Base", base);
240
dsdt_line(" 0x%08X, // Address Length", length);
241
dsdt_line(" )");
242
}
243
244
static int
245
basl_fwrite_dsdt(FILE *fp)
246
{
247
dsdt_fp = fp;
248
dsdt_error = 0;
249
dsdt_indent_level = 0;
250
251
dsdt_line("/*");
252
dsdt_line(" * bhyve DSDT template");
253
dsdt_line(" */");
254
dsdt_line("DefinitionBlock (\"bhyve_dsdt.aml\", \"DSDT\", 2,"
255
"\"BHYVE \", \"BVDSDT \", 0x00000001)");
256
dsdt_line("{");
257
dsdt_line(" Name (_S5, Package ()");
258
dsdt_line(" {");
259
dsdt_line(" 0x05,");
260
dsdt_line(" Zero,");
261
dsdt_line(" })");
262
263
pci_write_dsdt();
264
265
#ifdef __amd64__
266
dsdt_line("");
267
dsdt_line(" Scope (_SB.PC00)");
268
dsdt_line(" {");
269
dsdt_line(" Device (HPET)");
270
dsdt_line(" {");
271
dsdt_line(" Name (_HID, EISAID(\"PNP0103\"))");
272
dsdt_line(" Name (_UID, 0)");
273
dsdt_line(" Name (_CRS, ResourceTemplate ()");
274
dsdt_line(" {");
275
dsdt_indent(4);
276
dsdt_fixed_mem32(0xFED00000, 0x400);
277
dsdt_unindent(4);
278
dsdt_line(" })");
279
dsdt_line(" }");
280
dsdt_line(" }");
281
#endif
282
283
vmgenc_write_dsdt();
284
285
const struct acpi_device_list_entry *entry;
286
SLIST_FOREACH(entry, &acpi_devices, chain) {
287
BASL_EXEC(acpi_device_write_dsdt(entry->dev));
288
}
289
290
dsdt_line("}");
291
292
if (dsdt_error != 0)
293
return (dsdt_error);
294
295
EFFLUSH(fp);
296
297
return (0);
298
299
err_exit:
300
return (errno);
301
}
302
303
static int
304
basl_open(struct basl_fio *bf, int suffix)
305
{
306
int err;
307
308
err = 0;
309
310
if (suffix) {
311
strlcpy(bf->f_name, basl_stemplate, MAXPATHLEN);
312
bf->fd = mkstemps(bf->f_name, strlen(BHYVE_ASL_SUFFIX));
313
} else {
314
strlcpy(bf->f_name, basl_template, MAXPATHLEN);
315
bf->fd = mkstemp(bf->f_name);
316
}
317
318
if (bf->fd > 0) {
319
bf->fp = fdopen(bf->fd, "w+");
320
if (bf->fp == NULL) {
321
unlink(bf->f_name);
322
close(bf->fd);
323
}
324
} else {
325
err = 1;
326
}
327
328
return (err);
329
}
330
331
static void
332
basl_close(struct basl_fio *bf)
333
{
334
335
if (!basl_keep_temps)
336
unlink(bf->f_name);
337
fclose(bf->fp);
338
}
339
340
static int
341
basl_start(struct basl_fio *in, struct basl_fio *out)
342
{
343
int err;
344
345
err = basl_open(in, 0);
346
if (!err) {
347
err = basl_open(out, 1);
348
if (err) {
349
basl_close(in);
350
}
351
}
352
353
return (err);
354
}
355
356
static void
357
basl_end(struct basl_fio *in, struct basl_fio *out)
358
{
359
360
basl_close(in);
361
basl_close(out);
362
}
363
364
static int
365
basl_load(struct vmctx *ctx, int fd)
366
{
367
struct stat sb;
368
void *addr;
369
370
if (fstat(fd, &sb) < 0)
371
return (errno);
372
373
addr = calloc(1, sb.st_size);
374
if (addr == NULL)
375
return (ENOMEM);
376
377
if (read(fd, addr, sb.st_size) < 0)
378
return (errno);
379
380
struct basl_table *table;
381
382
uint8_t name[ACPI_NAMESEG_SIZE + 1] = { 0 };
383
memcpy(name, addr, sizeof(name) - 1 /* last char is '\0' */);
384
BASL_EXEC(basl_table_create(&table, ctx, name, BASL_TABLE_ALIGNMENT));
385
BASL_EXEC(basl_table_append_bytes(table, addr, sb.st_size));
386
387
free(addr);
388
return (0);
389
}
390
391
static int
392
basl_compile(struct vmctx *ctx, int (*fwrite_section)(FILE *))
393
{
394
struct basl_fio io[2];
395
static char iaslbuf[3*MAXPATHLEN + 10];
396
const char *fmt;
397
int err;
398
399
err = basl_start(&io[0], &io[1]);
400
if (!err) {
401
err = (*fwrite_section)(io[0].fp);
402
403
if (!err) {
404
/*
405
* iasl sends the results of the compilation to
406
* stdout. Shut this down by using the shell to
407
* redirect stdout to /dev/null, unless the user
408
* has requested verbose output for debugging
409
* purposes
410
*/
411
fmt = basl_verbose_iasl ?
412
"%s -p %s %s" :
413
"/bin/sh -c \"%s -p %s %s\" 1> /dev/null";
414
415
snprintf(iaslbuf, sizeof(iaslbuf),
416
fmt,
417
BHYVE_ASL_COMPILER,
418
io[1].f_name, io[0].f_name);
419
err = system(iaslbuf);
420
421
if (!err) {
422
/*
423
* Copy the aml output file into guest
424
* memory at the specified location
425
*/
426
err = basl_load(ctx, io[1].fd);
427
}
428
}
429
basl_end(&io[0], &io[1]);
430
}
431
432
return (err);
433
}
434
435
static int
436
basl_make_templates(void)
437
{
438
const char *tmpdir;
439
int err;
440
int len;
441
442
err = 0;
443
444
/*
445
*
446
*/
447
if ((tmpdir = getenv("BHYVE_TMPDIR")) == NULL || *tmpdir == '\0' ||
448
(tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') {
449
tmpdir = _PATH_TMP;
450
}
451
452
len = strlen(tmpdir);
453
454
if ((len + sizeof(BHYVE_ASL_TEMPLATE) + 1) < MAXPATHLEN) {
455
strcpy(basl_template, tmpdir);
456
while (len > 0 && basl_template[len - 1] == '/')
457
len--;
458
basl_template[len] = '/';
459
strcpy(&basl_template[len + 1], BHYVE_ASL_TEMPLATE);
460
} else
461
err = E2BIG;
462
463
if (!err) {
464
/*
465
* len has been initialized (and maybe adjusted) above
466
*/
467
if ((len + sizeof(BHYVE_ASL_TEMPLATE) + 1 +
468
sizeof(BHYVE_ASL_SUFFIX)) < MAXPATHLEN) {
469
strcpy(basl_stemplate, tmpdir);
470
basl_stemplate[len] = '/';
471
strcpy(&basl_stemplate[len + 1], BHYVE_ASL_TEMPLATE);
472
len = strlen(basl_stemplate);
473
strcpy(&basl_stemplate[len], BHYVE_ASL_SUFFIX);
474
} else
475
err = E2BIG;
476
}
477
478
return (err);
479
}
480
481
static int
482
build_dsdt(struct vmctx *const ctx)
483
{
484
BASL_EXEC(basl_compile(ctx, basl_fwrite_dsdt));
485
486
return (0);
487
}
488
489
static int
490
build_facs(struct vmctx *const ctx)
491
{
492
ACPI_TABLE_FACS facs;
493
struct basl_table *table;
494
495
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_FACS,
496
BASL_TABLE_ALIGNMENT_FACS));
497
498
memset(&facs, 0, sizeof(facs));
499
memcpy(facs.Signature, ACPI_SIG_FACS, ACPI_NAMESEG_SIZE);
500
facs.Length = sizeof(facs);
501
facs.Version = htole32(2);
502
BASL_EXEC(basl_table_append_bytes(table, &facs, sizeof(facs)));
503
504
return (0);
505
}
506
507
static int
508
build_fadt(struct vmctx *const ctx)
509
{
510
ACPI_TABLE_FADT fadt;
511
struct basl_table *table;
512
513
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_FADT,
514
BASL_TABLE_ALIGNMENT));
515
516
memset(&fadt, 0, sizeof(fadt));
517
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_FADT, 5, 1));
518
fadt.Facs = htole32(0); /* patched by basl */
519
fadt.Dsdt = htole32(0); /* patched by basl */
520
fadt.SciInterrupt = htole16(SCI_INT);
521
fadt.SmiCommand = htole32(SMI_CMD);
522
fadt.AcpiEnable = BHYVE_ACPI_ENABLE;
523
fadt.AcpiDisable = BHYVE_ACPI_DISABLE;
524
fadt.Pm1aEventBlock = htole32(PM1A_EVT_ADDR);
525
fadt.Pm1aControlBlock = htole32(PM1A_CNT_ADDR);
526
fadt.PmTimerBlock = htole32(IO_PMTMR);
527
fadt.Gpe0Block = htole32(IO_GPE0_BLK);
528
fadt.Pm1EventLength = 4;
529
fadt.Pm1ControlLength = 2;
530
fadt.PmTimerLength = 4;
531
fadt.Gpe0BlockLength = IO_GPE0_LEN;
532
fadt.Century = 0x32;
533
fadt.BootFlags = htole16(ACPI_FADT_NO_VGA | ACPI_FADT_NO_ASPM);
534
fadt.Flags = htole32(ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
535
ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_32BIT_TIMER |
536
ACPI_FADT_RESET_REGISTER | ACPI_FADT_HEADLESS |
537
ACPI_FADT_APIC_PHYSICAL);
538
basl_fill_gas(&fadt.ResetRegister, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
539
ACPI_GAS_ACCESS_WIDTH_BYTE, 0xCF9);
540
fadt.ResetValue = 6;
541
fadt.MinorRevision = 1;
542
fadt.XFacs = htole64(0); /* patched by basl */
543
fadt.XDsdt = htole64(0); /* patched by basl */
544
basl_fill_gas(&fadt.XPm1aEventBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0x20, 0,
545
ACPI_GAS_ACCESS_WIDTH_WORD, PM1A_EVT_ADDR);
546
basl_fill_gas(&fadt.XPm1bEventBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0, 0,
547
ACPI_GAS_ACCESS_WIDTH_UNDEFINED, 0);
548
basl_fill_gas(&fadt.XPm1aControlBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0x10,
549
0, ACPI_GAS_ACCESS_WIDTH_WORD, PM1A_CNT_ADDR);
550
basl_fill_gas(&fadt.XPm1bControlBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0, 0,
551
ACPI_GAS_ACCESS_WIDTH_UNDEFINED, 0);
552
basl_fill_gas(&fadt.XPm2ControlBlock, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
553
ACPI_GAS_ACCESS_WIDTH_UNDEFINED, 0);
554
basl_fill_gas(&fadt.XPmTimerBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0x20, 0,
555
ACPI_GAS_ACCESS_WIDTH_DWORD, IO_PMTMR);
556
basl_fill_gas(&fadt.XGpe0Block, ACPI_ADR_SPACE_SYSTEM_IO,
557
IO_GPE0_LEN * 8, 0, ACPI_GAS_ACCESS_WIDTH_BYTE, IO_GPE0_BLK);
558
basl_fill_gas(&fadt.XGpe1Block, ACPI_ADR_SPACE_SYSTEM_IO, 0, 0,
559
ACPI_GAS_ACCESS_WIDTH_UNDEFINED, 0);
560
basl_fill_gas(&fadt.SleepControl, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
561
ACPI_GAS_ACCESS_WIDTH_BYTE, 0);
562
basl_fill_gas(&fadt.SleepStatus, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
563
ACPI_GAS_ACCESS_WIDTH_BYTE, 0);
564
BASL_EXEC(basl_table_append_content(table, &fadt, sizeof(fadt)));
565
566
BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_FACS,
567
offsetof(ACPI_TABLE_FADT, Facs), sizeof(fadt.Facs)));
568
BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_DSDT,
569
offsetof(ACPI_TABLE_FADT, Dsdt), sizeof(fadt.Dsdt)));
570
BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_FACS,
571
offsetof(ACPI_TABLE_FADT, XFacs), sizeof(fadt.XFacs)));
572
BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_DSDT,
573
offsetof(ACPI_TABLE_FADT, XDsdt), sizeof(fadt.XDsdt)));
574
575
BASL_EXEC(basl_table_register_to_rsdt(table));
576
577
return (0);
578
}
579
580
#ifdef __amd64__
581
static int
582
build_hpet(struct vmctx *const ctx)
583
{
584
ACPI_TABLE_HPET hpet;
585
struct basl_table *table;
586
uint32_t hpet_capabilities;
587
int err;
588
589
err = vm_get_hpet_capabilities(ctx, &hpet_capabilities);
590
if (err != 0)
591
return (err);
592
593
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_HPET,
594
BASL_TABLE_ALIGNMENT));
595
596
memset(&hpet, 0, sizeof(hpet));
597
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_HPET, 1, 1));
598
hpet.Id = htole32(hpet_capabilities);
599
basl_fill_gas(&hpet.Address, ACPI_ADR_SPACE_SYSTEM_MEMORY, 0, 0,
600
ACPI_GAS_ACCESS_WIDTH_LEGACY, BHYVE_ADDRESS_HPET);
601
hpet.Flags = ACPI_HPET_PAGE_PROTECT4;
602
BASL_EXEC(basl_table_append_content(table, &hpet, sizeof(hpet)));
603
604
BASL_EXEC(basl_table_register_to_rsdt(table));
605
606
return (0);
607
}
608
#endif
609
610
static int
611
build_madt(struct vmctx *const ctx)
612
{
613
ACPI_TABLE_MADT madt;
614
ACPI_MADT_LOCAL_APIC madt_lapic;
615
ACPI_MADT_IO_APIC madt_ioapic;
616
ACPI_MADT_INTERRUPT_OVERRIDE madt_irq_override;
617
ACPI_MADT_LOCAL_APIC_NMI madt_lapic_nmi;
618
struct basl_table *table;
619
620
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_MADT,
621
BASL_TABLE_ALIGNMENT));
622
623
memset(&madt, 0, sizeof(madt));
624
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_MADT, 1, 1));
625
madt.Address = htole32(BHYVE_ADDRESS_LAPIC);
626
madt.Flags = htole32(ACPI_MADT_PCAT_COMPAT);
627
BASL_EXEC(basl_table_append_content(table, &madt, sizeof(madt)));
628
629
/* Local APIC for each CPU */
630
for (int i = 0; i < basl_ncpu; ++i) {
631
memset(&madt_lapic, 0, sizeof(madt_lapic));
632
madt_lapic.Header.Type = ACPI_MADT_TYPE_LOCAL_APIC;
633
madt_lapic.Header.Length = sizeof(madt_lapic);
634
madt_lapic.ProcessorId = i;
635
madt_lapic.Id = i;
636
madt_lapic.LapicFlags = htole32(ACPI_MADT_ENABLED);
637
BASL_EXEC(basl_table_append_bytes(table, &madt_lapic,
638
sizeof(madt_lapic)));
639
}
640
641
/* I/O APIC */
642
memset(&madt_ioapic, 0, sizeof(madt_ioapic));
643
madt_ioapic.Header.Type = ACPI_MADT_TYPE_IO_APIC;
644
madt_ioapic.Header.Length = sizeof(madt_ioapic);
645
madt_ioapic.Address = htole32(BHYVE_ADDRESS_IOAPIC);
646
BASL_EXEC(
647
basl_table_append_bytes(table, &madt_ioapic, sizeof(madt_ioapic)));
648
649
/* Legacy IRQ0 is connected to pin 2 of the I/O APIC */
650
memset(&madt_irq_override, 0, sizeof(madt_irq_override));
651
madt_irq_override.Header.Type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE;
652
madt_irq_override.Header.Length = sizeof(madt_irq_override);
653
madt_irq_override.GlobalIrq = htole32(2);
654
madt_irq_override.IntiFlags = htole16(
655
ACPI_MADT_POLARITY_ACTIVE_HIGH | ACPI_MADT_TRIGGER_EDGE);
656
BASL_EXEC(basl_table_append_bytes(table, &madt_irq_override,
657
sizeof(madt_irq_override)));
658
659
memset(&madt_irq_override, 0, sizeof(madt_irq_override));
660
madt_irq_override.Header.Type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE;
661
madt_irq_override.Header.Length = sizeof(madt_irq_override);
662
madt_irq_override.SourceIrq = SCI_INT;
663
madt_irq_override.GlobalIrq = htole32(SCI_INT);
664
madt_irq_override.IntiFlags = htole16(
665
ACPI_MADT_POLARITY_ACTIVE_LOW | ACPI_MADT_TRIGGER_LEVEL);
666
BASL_EXEC(basl_table_append_bytes(table, &madt_irq_override,
667
sizeof(madt_irq_override)));
668
669
/* Local APIC NMI is conntected to LINT 1 on all CPUs */
670
memset(&madt_lapic_nmi, 0, sizeof(madt_lapic_nmi));
671
madt_lapic_nmi.Header.Type = ACPI_MADT_TYPE_LOCAL_APIC_NMI;
672
madt_lapic_nmi.Header.Length = sizeof(madt_lapic_nmi);
673
madt_lapic_nmi.ProcessorId = 0xFF;
674
madt_lapic_nmi.IntiFlags = htole16(
675
ACPI_MADT_POLARITY_ACTIVE_HIGH | ACPI_MADT_TRIGGER_EDGE);
676
madt_lapic_nmi.Lint = 1;
677
BASL_EXEC(basl_table_append_bytes(table, &madt_lapic_nmi,
678
sizeof(madt_lapic_nmi)));
679
680
BASL_EXEC(basl_table_register_to_rsdt(table));
681
682
return (0);
683
}
684
685
static int
686
build_mcfg(struct vmctx *const ctx)
687
{
688
ACPI_TABLE_MCFG mcfg;
689
ACPI_MCFG_ALLOCATION mcfg_allocation;
690
struct basl_table *table;
691
692
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_MCFG,
693
BASL_TABLE_ALIGNMENT));
694
695
memset(&mcfg, 0, sizeof(mcfg));
696
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_MCFG, 1, 1));
697
BASL_EXEC(basl_table_append_content(table, &mcfg, sizeof(mcfg)));
698
699
memset(&mcfg_allocation, 0, sizeof(mcfg_allocation));
700
mcfg_allocation.Address = htole64(pci_ecfg_base());
701
mcfg_allocation.EndBusNumber = 0xFF;
702
BASL_EXEC(basl_table_append_bytes(table, &mcfg_allocation,
703
sizeof(mcfg_allocation)));
704
705
BASL_EXEC(basl_table_register_to_rsdt(table));
706
707
return (0);
708
}
709
710
static int
711
build_rsdp(struct vmctx *const ctx)
712
{
713
ACPI_TABLE_RSDP rsdp;
714
struct basl_table *table;
715
716
BASL_EXEC(basl_table_create(&table, ctx, ACPI_RSDP_NAME,
717
BASL_TABLE_ALIGNMENT));
718
719
memset(&rsdp, 0, sizeof(rsdp));
720
memcpy(rsdp.Signature, ACPI_SIG_RSDP, 8);
721
rsdp.Checksum = 0; /* patched by basl */
722
memcpy(rsdp.OemId, "BHYVE ", ACPI_OEM_ID_SIZE);
723
rsdp.Revision = 2;
724
rsdp.RsdtPhysicalAddress = htole32(0); /* patched by basl */
725
rsdp.Length = htole32(0); /* patched by basl */
726
rsdp.XsdtPhysicalAddress = htole64(0); /* patched by basl */
727
rsdp.ExtendedChecksum = 0; /* patched by basl */
728
BASL_EXEC(basl_table_append_bytes(table, &rsdp, sizeof(rsdp)));
729
730
BASL_EXEC(basl_table_add_checksum(table,
731
offsetof(ACPI_TABLE_RSDP, Checksum), 0, 20));
732
BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_RSDT,
733
offsetof(ACPI_TABLE_RSDP, RsdtPhysicalAddress),
734
sizeof(rsdp.RsdtPhysicalAddress)));
735
BASL_EXEC(basl_table_add_length(table,
736
offsetof(ACPI_TABLE_RSDP, Length), sizeof(rsdp.Length)));
737
BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_XSDT,
738
offsetof(ACPI_TABLE_RSDP, XsdtPhysicalAddress),
739
sizeof(rsdp.XsdtPhysicalAddress)));
740
BASL_EXEC(basl_table_add_checksum(table,
741
offsetof(ACPI_TABLE_RSDP, ExtendedChecksum), 0,
742
BASL_TABLE_CHECKSUM_LEN_FULL_TABLE));
743
744
return (0);
745
}
746
747
static int
748
build_spcr(struct vmctx *const ctx)
749
{
750
ACPI_TABLE_SPCR spcr;
751
struct basl_table *table;
752
753
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_SPCR,
754
BASL_TABLE_ALIGNMENT));
755
756
memset(&spcr, 0, sizeof(spcr));
757
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_SPCR, 1, 1));
758
spcr.InterfaceType = ACPI_DBG2_16550_COMPATIBLE;
759
basl_fill_gas(&spcr.SerialPort, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
760
ACPI_GAS_ACCESS_WIDTH_LEGACY, 0x3F8);
761
spcr.InterruptType = ACPI_SPCR_INTERRUPT_TYPE_8259;
762
spcr.PcInterrupt = 4;
763
spcr.BaudRate = ACPI_SPCR_BAUD_RATE_115200;
764
spcr.Parity = ACPI_SPCR_PARITY_NO_PARITY;
765
spcr.StopBits = ACPI_SPCR_STOP_BITS_1;
766
spcr.FlowControl = 3; /* RTS/CTS | DCD */
767
spcr.TerminalType = ACPI_SPCR_TERMINAL_TYPE_VT_UTF8;
768
BASL_EXEC(basl_table_append_content(table, &spcr, sizeof(spcr)));
769
770
BASL_EXEC(basl_table_register_to_rsdt(table));
771
772
return (0);
773
}
774
775
static int
776
build_srat(struct vmctx *const ctx)
777
{
778
ACPI_TABLE_SRAT srat;
779
ACPI_SRAT_MEM_AFFINITY srat_mem_affinity;
780
ACPI_SRAT_CPU_AFFINITY srat_cpu_affinity;
781
782
struct acpi_vcpu_affinity_entry *ep;
783
struct basl_table *table;
784
int segid, domain;
785
int _flags, _prot;
786
vm_ooffset_t _off;
787
size_t maplen;
788
uint64_t gpa;
789
int ret;
790
791
if (RB_EMPTY(&aff_head))
792
return (0);
793
794
memset(&srat, 0, sizeof(srat));
795
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_SRAT,
796
BASL_TABLE_ALIGNMENT));
797
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_SRAT, 1, 1));
798
srat.TableRevision = 1;
799
BASL_EXEC(basl_table_append_content(table, &srat, sizeof(srat)));
800
801
/*
802
* Iterate over the VM's memory maps and add
803
* a 'Memory Affinity Structure' for each mapping.
804
*/
805
gpa = 0;
806
while (1) {
807
ret = vm_mmap_getnext(ctx, &gpa, &segid, &_off, &maplen, &_prot,
808
&_flags);
809
if (ret) {
810
break;
811
}
812
813
if (segid >= VM_SYSMEM && segid < VM_BOOTROM) {
814
domain = segid - VM_SYSMEM;
815
} else {
816
/* Treat devmem segs as domain 0. */
817
domain = 0;
818
}
819
memset(&srat_mem_affinity, 0, sizeof(srat_mem_affinity));
820
srat_mem_affinity.Header.Type = ACPI_SRAT_TYPE_MEMORY_AFFINITY;
821
srat_mem_affinity.Header.Length = sizeof(srat_mem_affinity);
822
srat_mem_affinity.Flags |= ACPI_SRAT_MEM_ENABLED;
823
srat_mem_affinity.ProximityDomain = htole32(domain);
824
srat_mem_affinity.BaseAddress = htole64(gpa);
825
srat_mem_affinity.Length = htole64(maplen);
826
srat_mem_affinity.Flags = htole32(ACPI_SRAT_MEM_ENABLED);
827
BASL_EXEC(basl_table_append_bytes(table, &srat_mem_affinity,
828
sizeof(srat_mem_affinity)));
829
gpa += maplen;
830
}
831
832
/*
833
* Iterate over each "vCPUid to domain id" mapping and emit a
834
* 'Processor Local APIC/SAPIC Affinity Structure' for each entry.
835
*/
836
RB_FOREACH(ep, vcpu_affinities, &aff_head) {
837
memset(&srat_cpu_affinity, 0, sizeof(srat_cpu_affinity));
838
srat_cpu_affinity.Header.Type = ACPI_SRAT_TYPE_CPU_AFFINITY;
839
srat_cpu_affinity.Header.Length = sizeof(srat_cpu_affinity);
840
srat_cpu_affinity.ProximityDomainLo = (uint8_t)ep->domain;
841
srat_cpu_affinity.ApicId = (uint8_t)ep->vcpuid;
842
srat_cpu_affinity.Flags = htole32(ACPI_SRAT_CPU_USE_AFFINITY);
843
BASL_EXEC(basl_table_append_bytes(table, &srat_cpu_affinity,
844
sizeof(srat_cpu_affinity)));
845
}
846
847
BASL_EXEC(basl_table_register_to_rsdt(table));
848
849
return (0);
850
}
851
852
int
853
acpi_build(struct vmctx *ctx, int ncpu)
854
{
855
basl_ncpu = ncpu;
856
857
/*
858
* For debug, allow the user to have iasl compiler output sent
859
* to stdout rather than /dev/null
860
*/
861
if (getenv("BHYVE_ACPI_VERBOSE_IASL"))
862
basl_verbose_iasl = 1;
863
864
/*
865
* Allow the user to keep the generated ASL files for debugging
866
* instead of deleting them following use
867
*/
868
if (getenv("BHYVE_ACPI_KEEPTMPS"))
869
basl_keep_temps = 1;
870
871
BASL_EXEC(basl_init(ctx));
872
873
BASL_EXEC(basl_make_templates());
874
875
/*
876
* Generate ACPI tables and copy them into guest memory.
877
*
878
* According to UEFI Specification v6.3 chapter 5.1 the FADT should be
879
* the first table pointed to by XSDT. For that reason, build it as the
880
* first table after XSDT.
881
*/
882
BASL_EXEC(build_rsdp(ctx));
883
BASL_EXEC(build_fadt(ctx));
884
BASL_EXEC(build_madt(ctx));
885
#ifdef __amd64__
886
BASL_EXEC(build_hpet(ctx));
887
#endif
888
BASL_EXEC(build_mcfg(ctx));
889
BASL_EXEC(build_facs(ctx));
890
BASL_EXEC(build_spcr(ctx));
891
BASL_EXEC(build_srat(ctx));
892
893
/* Build ACPI device-specific tables such as a TPM2 table. */
894
const struct acpi_device_list_entry *entry;
895
SLIST_FOREACH(entry, &acpi_devices, chain) {
896
BASL_EXEC(acpi_device_build_table(entry->dev));
897
}
898
899
BASL_EXEC(build_dsdt(ctx));
900
901
BASL_EXEC(basl_finish());
902
903
return (0);
904
}
905
906