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 } 182