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 name Name of the ACPI device. 39 * @param hid Hardware ID of the ACPI device. 40 * @param crs Current resources used by the ACPI device. 41 */ 42 struct acpi_device { 43 struct vmctx *vm_ctx; 44 const char *name; 45 const char *hid; 46 SLIST_HEAD(acpi_resource_list, acpi_resource_list_entry) crs; 47 }; 48 49 int 50 acpi_device_create(struct acpi_device **const new_dev, 51 struct vmctx *const vm_ctx, const char *const name, const char *const hid) 52 { 53 if (new_dev == NULL || vm_ctx == NULL || name == NULL || hid == NULL) { 54 return (EINVAL); 55 } 56 57 struct acpi_device *const dev = calloc(1, sizeof(*dev)); 58 if (dev == NULL) { 59 return (ENOMEM); 60 } 61 62 dev->vm_ctx = vm_ctx; 63 dev->name = strdup(name); 64 dev->hid = strdup(hid); 65 SLIST_INIT(&dev->crs); 66 if (dev->name == NULL || dev->hid == NULL) { 67 acpi_device_destroy(dev); 68 return (ENOMEM); 69 } 70 71 const int error = acpi_tables_add_device(dev); 72 if (error) { 73 acpi_device_destroy(dev); 74 return (error); 75 } 76 77 *new_dev = dev; 78 79 return (0); 80 } 81 82 void 83 acpi_device_destroy(struct acpi_device *const dev) 84 { 85 if (dev == NULL) { 86 return; 87 } 88 89 struct acpi_resource_list_entry *res; 90 while (!SLIST_EMPTY(&dev->crs)) { 91 res = SLIST_FIRST(&dev->crs); 92 SLIST_REMOVE_HEAD(&dev->crs, chain); 93 free(res); 94 } 95 96 free(__DECONST(void *, dev->hid)); 97 free(__DECONST(void *, dev->name)); 98 free(dev); 99 } 100 101 int 102 acpi_device_add_res_fixed_ioport(struct acpi_device *const dev, 103 const UINT16 port, const UINT8 length) 104 { 105 if (dev == NULL) { 106 return (EINVAL); 107 } 108 109 struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res)); 110 if (res == NULL) { 111 return (ENOMEM); 112 } 113 114 res->type = ACPI_RESOURCE_TYPE_FIXED_IO; 115 res->data.FixedIo.Address = port; 116 res->data.FixedIo.AddressLength = length; 117 118 SLIST_INSERT_HEAD(&dev->crs, res, chain); 119 120 return (0); 121 } 122 123 int 124 acpi_device_add_res_fixed_memory32(struct acpi_device *const dev, 125 const UINT8 write_protected, const UINT32 address, const UINT32 length) 126 { 127 if (dev == NULL) { 128 return (EINVAL); 129 } 130 131 struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res)); 132 if (res == NULL) { 133 return (ENOMEM); 134 } 135 136 res->type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32; 137 res->data.FixedMemory32.WriteProtect = write_protected; 138 res->data.FixedMemory32.Address = address; 139 res->data.FixedMemory32.AddressLength = length; 140 141 SLIST_INSERT_HEAD(&dev->crs, res, chain); 142 143 return (0); 144 } 145 146 static void 147 acpi_device_write_dsdt_crs(const struct acpi_device *const dev) 148 { 149 const struct acpi_resource_list_entry *res; 150 SLIST_FOREACH(res, &dev->crs, chain) { 151 switch (res->type) { 152 case ACPI_RESOURCE_TYPE_FIXED_IO: 153 dsdt_fixed_ioport(res->data.FixedIo.Address, 154 res->data.FixedIo.AddressLength); 155 break; 156 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 157 dsdt_fixed_mem32(res->data.FixedMemory32.Address, 158 res->data.FixedMemory32.AddressLength); 159 break; 160 default: 161 assert(0); 162 break; 163 } 164 } 165 } 166 167 void 168 acpi_device_write_dsdt(const struct acpi_device *const dev) 169 { 170 if (dev == NULL) { 171 return; 172 } 173 174 dsdt_line(""); 175 dsdt_line(" Scope (\\_SB)"); 176 dsdt_line(" {"); 177 dsdt_line(" Device (%s)", dev->name); 178 dsdt_line(" {"); 179 dsdt_line(" Name (_HID, \"%s\")", dev->hid); 180 dsdt_line(" Name (_STA, 0x0F)"); 181 dsdt_line(" Name (_CRS, ResourceTemplate ()"); 182 dsdt_line(" {"); 183 dsdt_indent(4); 184 acpi_device_write_dsdt_crs(dev); 185 dsdt_unindent(4); 186 dsdt_line(" })"); 187 dsdt_line(" }"); 188 dsdt_line(" }"); 189 } 190