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