]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/acpi_device.c
makefs(8): do not print comma after the last super-block
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / acpi_device.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
5  * Author: Corvin Köhne <c.koehne@beckhoff.com>
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
21 /**
22  * List entry to enumerate all resources used by an ACPI device.
23  *
24  * @param chain Used to chain multiple elements together.
25  * @param type  Type of the ACPI resource.
26  * @param data  Data of the ACPI resource.
27  */
28 struct acpi_resource_list_entry {
29         SLIST_ENTRY(acpi_resource_list_entry) chain;
30         UINT32 type;
31         ACPI_RESOURCE_DATA data;
32 };
33
34 /**
35  * Holds information about an ACPI device.
36  *
37  * @param vm_ctx VM context the ACPI device was created in.
38  * @param emul   Device emulation struct. It contains some information like the
39                  name of the ACPI device and some device specific functions.
40  * @param crs    Current resources used by the ACPI device.
41  */
42 struct acpi_device {
43         struct vmctx *vm_ctx;
44         const struct acpi_device_emul *emul;
45         SLIST_HEAD(acpi_resource_list, acpi_resource_list_entry) crs;
46 };
47
48 int
49 acpi_device_create(struct acpi_device **const new_dev,
50     struct vmctx *const vm_ctx, const struct acpi_device_emul *const emul)
51 {
52         assert(new_dev != NULL);
53         assert(vm_ctx != NULL);
54         assert(emul != NULL);
55
56         struct acpi_device *const dev = calloc(1, sizeof(*dev));
57         if (dev == NULL) {
58                 return (ENOMEM);
59         }
60
61         dev->vm_ctx = vm_ctx;
62         dev->emul = emul;
63         SLIST_INIT(&dev->crs);
64
65         const int error = acpi_tables_add_device(dev);
66         if (error) {
67                 acpi_device_destroy(dev);
68                 return (error);
69         }
70
71         *new_dev = dev;
72
73         return (0);
74 }
75
76 void
77 acpi_device_destroy(struct acpi_device *const dev)
78 {
79         if (dev == NULL) {
80                 return;
81         }
82
83         struct acpi_resource_list_entry *res;
84         while (!SLIST_EMPTY(&dev->crs)) {
85                 res = SLIST_FIRST(&dev->crs);
86                 SLIST_REMOVE_HEAD(&dev->crs, chain);
87                 free(res);
88         }
89
90         free(dev);
91 }
92
93 int
94 acpi_device_add_res_fixed_ioport(struct acpi_device *const dev,
95     const UINT16 port, const UINT8 length)
96 {
97         if (dev == NULL) {
98                 return (EINVAL);
99         }
100
101         struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
102         if (res == NULL) {
103                 return (ENOMEM);
104         }
105
106         res->type = ACPI_RESOURCE_TYPE_FIXED_IO;
107         res->data.FixedIo.Address = port;
108         res->data.FixedIo.AddressLength = length;
109
110         SLIST_INSERT_HEAD(&dev->crs, res, chain);
111
112         return (0);
113 }
114
115 int
116 acpi_device_add_res_fixed_memory32(struct acpi_device *const dev,
117     const UINT8 write_protected, const UINT32 address, const UINT32 length)
118 {
119         if (dev == NULL) {
120                 return (EINVAL);
121         }
122
123         struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
124         if (res == NULL) {
125                 return (ENOMEM);
126         }
127
128         res->type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
129         res->data.FixedMemory32.WriteProtect = write_protected;
130         res->data.FixedMemory32.Address = address;
131         res->data.FixedMemory32.AddressLength = length;
132
133         SLIST_INSERT_HEAD(&dev->crs, res, chain);
134
135         return (0);
136 }
137
138 static void
139 acpi_device_write_dsdt_crs(const struct acpi_device *const dev)
140 {
141         const struct acpi_resource_list_entry *res;
142         SLIST_FOREACH(res, &dev->crs, chain) {
143                 switch (res->type) {
144                 case ACPI_RESOURCE_TYPE_FIXED_IO:
145                         dsdt_fixed_ioport(res->data.FixedIo.Address,
146                             res->data.FixedIo.AddressLength);
147                         break;
148                 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
149                         dsdt_fixed_mem32(res->data.FixedMemory32.Address,
150                             res->data.FixedMemory32.AddressLength);
151                         break;
152                 default:
153                         assert(0);
154                         break;
155                 }
156         }
157 }
158
159 void
160 acpi_device_write_dsdt(const struct acpi_device *const dev)
161 {
162         if (dev == NULL) {
163                 return;
164         }
165
166         dsdt_line("");
167         dsdt_line("  Scope (\\_SB)");
168         dsdt_line("  {");
169         dsdt_line("    Device (%s)", dev->emul->name);
170         dsdt_line("    {");
171         dsdt_line("      Name (_HID, \"%s\")", dev->emul->hid);
172         dsdt_line("      Name (_STA, 0x0F)");
173         dsdt_line("      Name (_CRS, ResourceTemplate ()");
174         dsdt_line("      {");
175         dsdt_indent(4);
176         acpi_device_write_dsdt_crs(dev);
177         dsdt_unindent(4);
178         dsdt_line("      })");
179         dsdt_line("    }");
180         dsdt_line("  }");
181 }