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