]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/tpm_device.c
Import device-tree files from Linux 6.3
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / tpm_device.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
5  * Author: Corvin Köhne <corvink@FreeBSD.org>
6  */
7
8 #include <sys/types.h>
9
10 #include <assert.h>
11 #include <err.h>
12 #include <errno.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <vmmapi.h>
16
17 #include "acpi_device.h"
18 #include "config.h"
19 #include "tpm_device.h"
20 #include "tpm_emul.h"
21 #include "tpm_intf.h"
22
23 #define TPM_ACPI_DEVICE_NAME "TPM"
24 #define TPM_ACPI_HARDWARE_ID "MSFT0101"
25
26 SET_DECLARE(tpm_emul_set, struct tpm_emul);
27 SET_DECLARE(tpm_intf_set, struct tpm_intf);
28
29 struct tpm_device {
30         struct vmctx *vm_ctx;
31         struct acpi_device *acpi_dev;
32         struct tpm_emul *emul;
33         void *emul_sc;
34         struct tpm_intf *intf;
35         void *intf_sc;
36 };
37
38 static int
39 tpm_build_acpi_table(const struct acpi_device *const dev)
40 {
41         const struct tpm_device *const tpm = acpi_device_get_softc(dev);
42
43         if (tpm->intf->build_acpi_table == NULL) {
44                 return (0);
45         }
46
47         return (tpm->intf->build_acpi_table(tpm->intf_sc, tpm->vm_ctx));
48 }
49
50 static const struct acpi_device_emul tpm_acpi_device_emul = {
51         .name = TPM_ACPI_DEVICE_NAME,
52         .hid = TPM_ACPI_HARDWARE_ID,
53         .build_table = tpm_build_acpi_table,
54 };
55
56 void
57 tpm_device_destroy(struct tpm_device *const dev)
58 {
59         if (dev == NULL)
60                 return;
61
62         if (dev->intf != NULL && dev->intf->deinit != NULL)
63                 dev->intf->deinit(dev->intf_sc);
64         if (dev->emul != NULL && dev->emul->deinit != NULL)
65                 dev->emul->deinit(dev->emul_sc);
66
67         acpi_device_destroy(dev->acpi_dev);
68         free(dev);
69 }
70
71 int
72 tpm_device_create(struct tpm_device **const new_dev, struct vmctx *const vm_ctx,
73     nvlist_t *const nvl)
74 {
75         struct tpm_device *dev = NULL;
76         struct tpm_emul **ppemul;
77         struct tpm_intf **ppintf;
78         const char *value;
79         int error;
80
81         if (new_dev == NULL || vm_ctx == NULL) {
82                 error = EINVAL;
83                 goto err_out;
84         }
85
86         set_config_value_node_if_unset(nvl, "intf", "crb");
87
88         value = get_config_value_node(nvl, "version");
89         assert(value != NULL);
90         if (strcmp(value, "2.0")) {
91                 warnx("%s: unsupported tpm version %s", __func__, value);
92                 error = EINVAL;
93                 goto err_out;
94         }
95
96         dev = calloc(1, sizeof(*dev));
97         if (dev == NULL) {
98                 error = ENOMEM;
99                 goto err_out;
100         }
101
102         dev->vm_ctx = vm_ctx;
103
104         error = acpi_device_create(&dev->acpi_dev, dev, dev->vm_ctx,
105             &tpm_acpi_device_emul);
106         if (error)
107                 goto err_out;
108
109         value = get_config_value_node(nvl, "type");
110         assert(value != NULL);
111         SET_FOREACH(ppemul, tpm_emul_set) {
112                 if (strcmp(value, (*ppemul)->name))
113                         continue;
114                 dev->emul = *ppemul;
115                 break;
116         }
117         if (dev->emul == NULL) {
118                 warnx("TPM emulation \"%s\" not found", value);
119                 error = EINVAL;
120                 goto err_out;
121         }
122
123         if (dev->emul->init) {
124                 error = dev->emul->init(&dev->emul_sc, nvl);
125                 if (error)
126                         goto err_out;
127         }
128
129         value = get_config_value_node(nvl, "intf");
130         SET_FOREACH(ppintf, tpm_intf_set) {
131                 if (strcmp(value, (*ppintf)->name)) {
132                         continue;
133                 }
134                 dev->intf = *ppintf;
135                 break;
136         }
137         if (dev->intf == NULL) {
138                 warnx("TPM interface \"%s\" not found", value);
139                 error = EINVAL;
140                 goto err_out;
141         }
142
143         if (dev->intf->init) {
144                 error = dev->intf->init(&dev->intf_sc, dev->emul, dev->emul_sc);
145                 if (error)
146                         goto err_out;
147         }
148
149         *new_dev = dev;
150
151         return (0);
152
153 err_out:
154         tpm_device_destroy(dev);
155
156         return (error);
157 }