Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bhyve/acpi_device.c
105240 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
5
* Author: Corvin Köhne <[email protected]>
6
*/
7
8
#include <sys/param.h>
9
#include <sys/queue.h>
10
11
#include <machine/vmm.h>
12
13
#include <assert.h>
14
#include <err.h>
15
#include <errno.h>
16
#include <vmmapi.h>
17
18
#include "acpi.h"
19
#include "acpi_device.h"
20
#include "basl.h"
21
22
/**
23
* List entry to enumerate all resources used by an ACPI device.
24
*
25
* @param chain Used to chain multiple elements together.
26
* @param type Type of the ACPI resource.
27
* @param data Data of the ACPI resource.
28
*/
29
struct acpi_resource_list_entry {
30
SLIST_ENTRY(acpi_resource_list_entry) chain;
31
UINT32 type;
32
ACPI_RESOURCE_DATA data;
33
};
34
35
/**
36
* Holds information about an ACPI device.
37
*
38
* @param vm_ctx VM context the ACPI device was created in.
39
* @param softc A pointer to the software context of the ACPI device.
40
* @param emul Device emulation struct. It contains some information like the
41
name of the ACPI device and some device specific functions.
42
* @param crs Current resources used by the ACPI device.
43
*/
44
struct acpi_device {
45
struct vmctx *vm_ctx;
46
void *softc;
47
const struct acpi_device_emul *emul;
48
SLIST_HEAD(acpi_resource_list, acpi_resource_list_entry) crs;
49
};
50
51
int
52
acpi_device_create(struct acpi_device **const new_dev, void *const softc,
53
struct vmctx *const vm_ctx, const struct acpi_device_emul *const emul)
54
{
55
assert(new_dev != NULL);
56
assert(vm_ctx != NULL);
57
assert(emul != NULL);
58
59
struct acpi_device *const dev = calloc(1, sizeof(*dev));
60
if (dev == NULL) {
61
return (ENOMEM);
62
}
63
64
dev->vm_ctx = vm_ctx;
65
dev->softc = softc;
66
dev->emul = emul;
67
SLIST_INIT(&dev->crs);
68
69
const int error = acpi_tables_add_device(dev);
70
if (error) {
71
acpi_device_destroy(dev);
72
return (error);
73
}
74
75
*new_dev = dev;
76
77
return (0);
78
}
79
80
void
81
acpi_device_destroy(struct acpi_device *const dev)
82
{
83
if (dev == NULL) {
84
return;
85
}
86
87
struct acpi_resource_list_entry *res;
88
while (!SLIST_EMPTY(&dev->crs)) {
89
res = SLIST_FIRST(&dev->crs);
90
SLIST_REMOVE_HEAD(&dev->crs, chain);
91
free(res);
92
}
93
94
free(dev);
95
}
96
97
int
98
acpi_device_add_res_fixed_ioport(struct acpi_device *const dev,
99
const UINT16 port, const UINT8 length)
100
{
101
if (dev == NULL) {
102
return (EINVAL);
103
}
104
105
struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
106
if (res == NULL) {
107
return (ENOMEM);
108
}
109
110
res->type = ACPI_RESOURCE_TYPE_FIXED_IO;
111
res->data.FixedIo.Address = port;
112
res->data.FixedIo.AddressLength = length;
113
114
SLIST_INSERT_HEAD(&dev->crs, res, chain);
115
116
return (0);
117
}
118
119
int
120
acpi_device_add_res_fixed_memory32(struct acpi_device *const dev,
121
const UINT8 write_protected, const UINT32 address, const UINT32 length)
122
{
123
if (dev == NULL) {
124
return (EINVAL);
125
}
126
127
struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
128
if (res == NULL) {
129
return (ENOMEM);
130
}
131
132
res->type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
133
res->data.FixedMemory32.WriteProtect = write_protected;
134
res->data.FixedMemory32.Address = address;
135
res->data.FixedMemory32.AddressLength = length;
136
137
SLIST_INSERT_HEAD(&dev->crs, res, chain);
138
139
return (0);
140
}
141
142
void *
143
acpi_device_get_softc(const struct acpi_device *const dev)
144
{
145
assert(dev != NULL);
146
147
return (dev->softc);
148
}
149
150
int
151
acpi_device_build_table(const struct acpi_device *const dev)
152
{
153
assert(dev != NULL);
154
assert(dev->emul != NULL);
155
156
if (dev->emul->build_table != NULL) {
157
return (dev->emul->build_table(dev));
158
}
159
160
return (0);
161
}
162
163
static int
164
acpi_device_write_dsdt_crs(const struct acpi_device *const dev)
165
{
166
const struct acpi_resource_list_entry *res;
167
SLIST_FOREACH(res, &dev->crs, chain) {
168
switch (res->type) {
169
case ACPI_RESOURCE_TYPE_FIXED_IO:
170
dsdt_fixed_ioport(res->data.FixedIo.Address,
171
res->data.FixedIo.AddressLength);
172
break;
173
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
174
dsdt_fixed_mem32(res->data.FixedMemory32.Address,
175
res->data.FixedMemory32.AddressLength);
176
break;
177
default:
178
assert(0);
179
break;
180
}
181
}
182
183
return (0);
184
}
185
186
int
187
acpi_device_write_dsdt(const struct acpi_device *const dev)
188
{
189
assert(dev != NULL);
190
191
dsdt_line("");
192
dsdt_line(" Scope (\\_SB)");
193
dsdt_line(" {");
194
dsdt_line(" Device (%s)", dev->emul->name);
195
dsdt_line(" {");
196
dsdt_line(" Name (_HID, \"%s\")", dev->emul->hid);
197
dsdt_line(" Name (_STA, 0x0F)");
198
dsdt_line(" Name (_CRS, ResourceTemplate ()");
199
dsdt_line(" {");
200
dsdt_indent(4);
201
BASL_EXEC(acpi_device_write_dsdt_crs(dev));
202
dsdt_unindent(4);
203
dsdt_line(" })");
204
if (dev->emul->write_dsdt != NULL) {
205
dsdt_indent(3);
206
BASL_EXEC(dev->emul->write_dsdt(dev));
207
dsdt_unindent(3);
208
}
209
dsdt_line(" }");
210
dsdt_line(" }");
211
212
return (0);
213
}
214
215