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