]>
Commit | Line | Data |
---|---|---|
ac90053d EA |
1 | /* |
2 | * tpm_tis_isa.c - QEMU's TPM TIS ISA Device | |
3 | * | |
4 | * Copyright (C) 2006,2010-2013 IBM Corporation | |
5 | * | |
6 | * Authors: | |
7 | * Stefan Berger <stefanb@us.ibm.com> | |
8 | * David Safford <safford@us.ibm.com> | |
9 | * | |
10 | * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at> | |
11 | * | |
12 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
13 | * See the COPYING file in the top-level directory. | |
14 | * | |
15 | * Implementation of the TIS interface according to specs found at | |
16 | * http://www.trustedcomputinggroup.org. This implementation currently | |
17 | * supports version 1.3, 21 March 2013 | |
18 | * In the developers menu choose the PC Client section then find the TIS | |
19 | * specification. | |
20 | * | |
21 | * TPM TIS for TPM 2 implementation following TCG PC Client Platform | |
6eedbb5b | 22 | * TPM Profile (PTP) Specification, Family 2.0, Revision 00.43 |
ac90053d EA |
23 | */ |
24 | ||
25 | #include "qemu/osdep.h" | |
26 | #include "hw/isa/isa.h" | |
27 | #include "hw/qdev-properties.h" | |
28 | #include "migration/vmstate.h" | |
40214766 | 29 | #include "hw/acpi/tpm.h" |
a3500613 | 30 | #include "tpm_prop.h" |
ac90053d | 31 | #include "tpm_tis.h" |
db1015e9 | 32 | #include "qom/object.h" |
168e3aa7 | 33 | #include "hw/acpi/acpi_aml_interface.h" |
ac90053d | 34 | |
db1015e9 | 35 | struct TPMStateISA { |
ac90053d EA |
36 | /*< private >*/ |
37 | ISADevice parent_obj; | |
38 | ||
39 | /*< public >*/ | |
40 | TPMState state; /* not a QOM object */ | |
db1015e9 | 41 | }; |
ac90053d | 42 | |
8063396b | 43 | OBJECT_DECLARE_SIMPLE_TYPE(TPMStateISA, TPM_TIS_ISA) |
ac90053d EA |
44 | |
45 | static int tpm_tis_pre_save_isa(void *opaque) | |
46 | { | |
47 | TPMStateISA *isadev = opaque; | |
48 | ||
49 | return tpm_tis_pre_save(&isadev->state); | |
50 | } | |
51 | ||
52 | static const VMStateDescription vmstate_tpm_tis_isa = { | |
53 | .name = "tpm-tis", | |
54 | .version_id = 0, | |
55 | .pre_save = tpm_tis_pre_save_isa, | |
56 | .fields = (VMStateField[]) { | |
57 | VMSTATE_BUFFER(state.buffer, TPMStateISA), | |
58 | VMSTATE_UINT16(state.rw_offset, TPMStateISA), | |
59 | VMSTATE_UINT8(state.active_locty, TPMStateISA), | |
60 | VMSTATE_UINT8(state.aborting_locty, TPMStateISA), | |
61 | VMSTATE_UINT8(state.next_locty, TPMStateISA), | |
62 | ||
63 | VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, | |
64 | vmstate_locty, TPMLocality), | |
65 | ||
66 | VMSTATE_END_OF_LIST() | |
67 | } | |
68 | }; | |
69 | ||
70 | static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) | |
71 | { | |
72 | TPMStateISA *isadev = TPM_TIS_ISA(ti); | |
73 | TPMState *s = &isadev->state; | |
74 | ||
75 | tpm_tis_request_completed(s, ret); | |
76 | } | |
77 | ||
78 | static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) | |
79 | { | |
80 | TPMStateISA *isadev = TPM_TIS_ISA(ti); | |
81 | TPMState *s = &isadev->state; | |
82 | ||
83 | return tpm_tis_get_tpm_version(s); | |
84 | } | |
85 | ||
86 | static void tpm_tis_isa_reset(DeviceState *dev) | |
87 | { | |
88 | TPMStateISA *isadev = TPM_TIS_ISA(dev); | |
89 | TPMState *s = &isadev->state; | |
90 | ||
91 | return tpm_tis_reset(s); | |
92 | } | |
93 | ||
94 | static Property tpm_tis_isa_properties[] = { | |
95 | DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), | |
96 | DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), | |
97 | DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), | |
98 | DEFINE_PROP_END_OF_LIST(), | |
99 | }; | |
100 | ||
101 | static void tpm_tis_isa_initfn(Object *obj) | |
102 | { | |
103 | TPMStateISA *isadev = TPM_TIS_ISA(obj); | |
104 | TPMState *s = &isadev->state; | |
105 | ||
106 | memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, | |
107 | s, "tpm-tis-mmio", | |
108 | TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); | |
109 | } | |
110 | ||
111 | static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) | |
112 | { | |
113 | TPMStateISA *isadev = TPM_TIS_ISA(dev); | |
114 | TPMState *s = &isadev->state; | |
115 | ||
116 | if (!tpm_find()) { | |
117 | error_setg(errp, "at most one TPM device is permitted"); | |
118 | return; | |
119 | } | |
120 | ||
121 | if (!s->be_driver) { | |
122 | error_setg(errp, "'tpmdev' property is required"); | |
123 | return; | |
124 | } | |
125 | if (s->irq_num > 15) { | |
126 | error_setg(errp, "IRQ %d is outside valid range of 0 to 15", | |
127 | s->irq_num); | |
128 | return; | |
129 | } | |
130 | ||
215caca6 | 131 | s->irq = isa_get_irq(ISA_DEVICE(dev), s->irq_num); |
ac90053d EA |
132 | |
133 | memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), | |
134 | TPM_TIS_ADDR_BASE, &s->mmio); | |
135 | ||
136 | if (s->ppi_enabled) { | |
137 | tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), | |
138 | TPM_PPI_ADDR_BASE, OBJECT(dev)); | |
139 | } | |
140 | } | |
141 | ||
168e3aa7 IM |
142 | static void build_tpm_tis_isa_aml(AcpiDevAmlIf *adev, Aml *scope) |
143 | { | |
144 | Aml *dev, *crs; | |
145 | TPMStateISA *isadev = TPM_TIS_ISA(adev); | |
146 | TPMIf *ti = TPM_IF(isadev); | |
147 | ||
148 | dev = aml_device("TPM"); | |
149 | if (tpm_tis_isa_get_tpm_version(ti) == TPM_VERSION_2_0) { | |
150 | aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); | |
151 | aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device"))); | |
152 | } else { | |
153 | aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); | |
154 | } | |
155 | aml_append(dev, aml_name_decl("_UID", aml_int(1))); | |
156 | aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); | |
157 | crs = aml_resource_template(); | |
158 | aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE, | |
159 | AML_READ_WRITE)); | |
160 | /* | |
161 | * FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs, | |
162 | * fix default TPM_TIS_IRQ value there to use some unused IRQ | |
163 | */ | |
164 | /* aml_append(crs, aml_irq_no_flags(isadev->state.irq_num)); */ | |
165 | aml_append(dev, aml_name_decl("_CRS", crs)); | |
166 | tpm_build_ppi_acpi(ti, dev); | |
167 | aml_append(scope, dev); | |
168 | } | |
169 | ||
ac90053d EA |
170 | static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) |
171 | { | |
172 | DeviceClass *dc = DEVICE_CLASS(klass); | |
173 | TPMIfClass *tc = TPM_IF_CLASS(klass); | |
168e3aa7 | 174 | AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); |
ac90053d EA |
175 | |
176 | device_class_set_props(dc, tpm_tis_isa_properties); | |
177 | dc->vmsd = &vmstate_tpm_tis_isa; | |
178 | tc->model = TPM_MODEL_TPM_TIS; | |
179 | dc->realize = tpm_tis_isa_realizefn; | |
180 | dc->reset = tpm_tis_isa_reset; | |
181 | tc->request_completed = tpm_tis_isa_request_completed; | |
182 | tc->get_version = tpm_tis_isa_get_tpm_version; | |
14e996ef | 183 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); |
168e3aa7 | 184 | adevc->build_dev_aml = build_tpm_tis_isa_aml; |
ac90053d EA |
185 | } |
186 | ||
187 | static const TypeInfo tpm_tis_isa_info = { | |
188 | .name = TYPE_TPM_TIS_ISA, | |
189 | .parent = TYPE_ISA_DEVICE, | |
190 | .instance_size = sizeof(TPMStateISA), | |
191 | .instance_init = tpm_tis_isa_initfn, | |
192 | .class_init = tpm_tis_isa_class_init, | |
193 | .interfaces = (InterfaceInfo[]) { | |
194 | { TYPE_TPM_IF }, | |
168e3aa7 | 195 | { TYPE_ACPI_DEV_AML_IF }, |
ac90053d EA |
196 | { } |
197 | } | |
198 | }; | |
199 | ||
200 | static void tpm_tis_isa_register(void) | |
201 | { | |
202 | type_register_static(&tpm_tis_isa_info); | |
203 | } | |
204 | ||
205 | type_init(tpm_tis_isa_register) |