1 /*
2 * Copyright (C) 2003-2015 FreeIPMI Core Team
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* HAVE_CONFIG_H */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #ifdef STDC_HEADERS
26 #include <string.h>
27 #endif /* STDC_HEADERS */
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif /* HAVE_UNISTD_H */
34 #if HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif /* HAVE_FCNTL_H */
37 #include <assert.h>
38 #include <errno.h>
39
40 #include "freeipmi/locate/ipmi-locate.h"
41 #include "freeipmi/fiid/fiid.h"
42 #include "freeipmi/driver/ipmi-ssif-driver.h"
43
44 #include "ipmi-locate-defs.h"
45 #include "ipmi-locate-trace.h"
46 #include "ipmi-locate-util.h"
47
48 #include "libcommon/ipmi-fiid-util.h"
49
50 #include "freeipmi-portability.h"
51
52 #define IPMI_ACPI_ADDRESS_SPACE_ID_SYSTEM_MEMORY IPMI_ADDRESS_SPACE_ID_SYSTEM_MEMORY
53 #define IPMI_ACPI_ADDRESS_SPACE_ID_SYSTEM_IO IPMI_ADDRESS_SPACE_ID_SYSTEM_IO
54 #define IPMI_ACPI_ADDRESS_SPACE_ID_SMBUS IPMI_ADDRESS_SPACE_ID_SMBUS
55
56 /* Certain ACPI table field widths are architecture specific */
57 #define IPMI_ACPI_MACHINE_WIDTH (sizeof (void *) * 8)
58
59 /* Constants used in searching for the RSDP (Root System Description
60 Pointer) in low memory */
61 #define IPMI_ACPI_LO_RSDP_WINDOW_BASE 0 /* Physical Address */
62 #define IPMI_ACPI_HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */
63 #define IPMI_ACPI_LO_RSDP_WINDOW_SIZE 0x400
64 #define IPMI_ACPI_HI_RSDP_WINDOW_SIZE 0x20000
65 #define IPMI_ACPI_RSDP_SCAN_STEP 16
66
67 /*
68 * Values for description table header signatures
69 */
70 #define IPMI_ACPI_RSDP_NAME "RSDP"
71 #define IPMI_ACPI_RSDP_SIG "RSD PTR " /* RSDT Pointer signature */
72 #define IPMI_ACPI_APIC_SIG "APIC" /* Multiple APIC Description Table */
73 #define IPMI_ACPI_DSDT_SIG "DSDT" /* Differentiated System Description Table */
74 #define IPMI_ACPI_FADT_SIG "FACP" /* Fixed ACPI Description Table */
75 #define IPMI_ACPI_FACS_SIG "FACS" /* Firmware ACPI Control Structure */
76 #define IPMI_ACPI_PSDT_SIG "PSDT" /* Persistent System Description Table */
77 #define IPMI_ACPI_RSDT_SIG "RSDT" /* Root System Description Table */
78 #define IPMI_ACPI_XSDT_SIG "XSDT" /* Extended System Description Table */
79 #define IPMI_ACPI_SSDT_SIG "SSDT" /* Secondary System Description Table */
80 #define IPMI_ACPI_SBST_SIG "SBST" /* Smart Battery Specification Table */
81 #define IPMI_ACPI_SPIC_SIG "SPIC" /* IOSAPIC table */
82 #define IPMI_ACPI_BOOT_SIG "BOOT" /* Boot table */
83 #define IPMI_ACPI_SPMI_SIG "SPMI" /* Service Processor Management Interface */
84
85 /* RSDP checksums */
86 #define IPMI_ACPI_RSDP_CHECKSUM_LENGTH 20
87 #define IPMI_ACPI_RSDP_XCHECKSUM_LENGTH 36
88
89 fiid_template_t tmpl_acpi_rsdp_descriptor = /* Root System Descriptor Pointer */
90 {
91 /* ACPI signature, contains "RSD PTR " */
92 { 64, "signature", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
93 /* To make sum of struct == 0 */
94 { 8, "checksum", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
95 /* OEM identification */
96 { 48, "oem_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
97 /* Must be 0 for 1.0, 2 for 2.0 */
98 { 8, "revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
99 /* 32-bit physical address of RSDT */
100 { 32, "rsdt_physical_address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
101 /* XSDT Length in bytes including hdr */
102 { 32, "length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
103 /* 64-bit physical address of XSDT */
104 { 64, "xsdt_physical_address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
105 /* Checksum of entire table */
106 { 8, "extended_checksum", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
107 /* Reserved field must be 0 */
108 { 24, "reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
109 { 0, "", 0}
110 };
111
112 fiid_template_t tmpl_acpi_table_hdr =
113 {
114 /* ACPI signature (4 ASCII characters) */
115 { 32, "signature", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
116 /* Length of table, in bytes, including header */
117 { 32, "length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
118 /* ACPI Specification minor version # */
119 { 8, "revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
120 /* To make sum of entire table == 0 */
121 { 8, "checksum", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
122 /* OEM identification */
123 { 48, "oem_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
124 /* OEM table identification */
125 { 64, "oem_table_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
126 /* OEM revision number */
127 { 32, "oem_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
128 /* ASL compiler vendor ID */
129 { 32, "asl_compiler_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
130 /* ASL compiler revision number */
131 { 32, "asl_compiler_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
132 { 0, "", 0}
133 };
134
135 fiid_template_t tmpl_acpi_spmi_table_descriptor =
136 {
137 /* `SPMI'. Signature for the Service Processor Management
138 Interface Table. */
139 { 32, "signature", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
140 /* Length, in bytes, of the entire Service Processor Management
141 Interface Table. */
142 { 32, "length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
143 /* 5 */
144 { 8, "revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
145 /* Entire table must sum to zero. */
146 { 8, "checksum", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
147 /* OEM ID. Per ACPI specification. An OEM-supplied string that
148 identifies the OEM. */
149 { 48, "oemid", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
150 /* For the Service Processor Management Interface Table,
151 the table ID is the manufacturer model ID
152 (assigned by the OEM identified by "OEM ID"). */
153 { 64, "oem_table_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
154 /* OEM revision of Service Processor Management Interface
155 Table for supplied the given OEM Table ID. Per ACPI, this is
156 "An OEM-supplied revision number. Larger numbers are
157 assumed to be newer revisions." */
158 { 32, "oem_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
159 /* Vendor ID of utility that created the table. For the tables
160 containing Definition Blocks, this is the ID for the ASL
161 Compiler. */
162 { 32, "creator_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
163 /* Revision of utility that created the table. For the tables
164 containing Definition Blocks, this is the revision
165 for the ASL Compiler. */
166 { 32, "creator_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
167 /* Indicates the type of IPMI interface:
168 0 Reserved
169 1 Keyboard Controller Style (KCS)
170 2 Server Management Interface Chip (SMIC)
171 3 Block Transfer (BT)
172 4 SMBus System Interface (SSIF)
173 5-255 Reserved */
174 { 8, "interface_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
175 /* This field must always be 01h to be compatible with any
176 software that implements previous
177 versions of this spec. */
178 { 8, "ipmi_legacy", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
179 /* Identifies the IPMI specification revision,
180 in BCD format, to which the interface
181 was designed. The first byte holds the
182 most significant digits, while second byte holds
183 the least significant digits of the revision,
184 e.g. a value of 0x0150 indicates the interface is
185 compatible with IPMI version v1.5. */
186 /* {16, "specification_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED}, */
187 { 8, "specification_revision.minor", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
188 { 8, "specification_revision.major", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
189 /* Interrupt type(s) used by
190 the interface:
191 [0] - SCI triggered through GPE
192 (use 0b for SSIF)
193 0 = not supported
194 1 = supported */
195 { 1, "interrupt_type.sci_triggered_thru_gpe", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
196 /* [1] - I/O APIC/SAPIC interrupt
197 (Global System Interrupt) */
198 { 1, "interrupt_type.io_apic_sapic_interrupt", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
199 /* [7:2] - Reserved (must be 0) */
200 { 6, "interrupt_type.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
201 /* The bit assignment of the SCI interrupt within the GPEx_STS
202 register of a GPE described if the FADT that the interface
203 triggers. (Note: This field is valid only if Bit[0] of the Interrupt
204 Type field is set. Otherwise set to 00h.) */
205 { 8, "gpe", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
206 /* 00h */
207 { 8, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
208 /* [0] - PCI Device Flag. For PCI IPMI devices,
209 this bit is set. For non-PCI devices, this bit is cleared.
210 When this bit is cleared, the PCI Segment Group, Bus,
211 Device and Function Number fields combined corresponds
212 to the ACPI _UID value of the device whose _HID or _CID
213 contains IPI0001 plug and play ID.
214 _UID must be an integer. Byte 60 contains the least
215 significant byte of the _UID value. Set to 0b for SSIF. */
216 { 1, "pci_device_flag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
217 /* [7:1] - Reserved */
218 { 7, "pci_device_flag.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
219 /* The I/O APIC or I/O SAPIC Global System
220 Interrupt used by the interface.
221 (Note: This field is valid only if Bit[1] of the
222 Interrupt Type field is set.
223 Otherwise set to 00h.) */
224 { 32, "global_system_interrupt", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
225 /* The base address of the interface register
226 set described using the Generic Address Structure
227 (GAS, See [ACPI 2.0] for the
228 definition). The Address_Space_ID field in
229 the GAS can only be of the value of 0 (System Memory),
230 1 (System IO), and 4 (SMBus).
231 All other values are not permitted.
232 For SSIF:
233 The Address_Space_ID = 4 and the address field of the GAS
234 holds the 7-bit slave address of the BMC on the host SMBus
235 in the least significant byte. Note that the slave address is
236 stored with the 7-bit slave address in the least
237 significant 7-
238 bits of the byte, and the most significant
239 bit of the byte set to
240 0b.
241 Register_Bit_Width = 0
242 Register_Bit_Offset = 0
243 Address_Size field = 1 (Byte access)
244 Address = 7-bit SMBus address of BMC
245 SSIF */
246 /* {96, "base_address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED}, */
247 /* Address space where
248 struct or register
249 exists. */
250 { 8, "base_address.address_space_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
251 /* Size in bits of given
252 register */
253 { 8, "base_address.register_bit_width", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
254 /* Bit offset within the
255 register */
256 { 8, "base_address.register_bit_offset", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
257 /* Must be 0 */
258 { 8, "base_address.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
259 /* 64-bit address of
260 struct or register */
261 { 64, "base_address.address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
262 /* for IPMI cards not located on PCI */
263 { 32, "uid", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
264 /* This field must always be null (0x00) to be compatible with
265 any software that implements previous versions of this spec.
266 This field is a deprecated "SPMI ID Field". Implementations
267 based on pre-IPMI v2.0 versions of SPMI may contain a null-
268 terminated string here. */
269 { 8, "reserved2", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
270 { 0, "", 0}
271 };
272
273 fiid_template_t tmpl_acpi_spmi_table_descriptor_ssif =
274 {
275 /* `SPMI'. Signature for the Service Processor Management
276 Interface Table. */
277 { 32, "signature", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
278 /* Length, in bytes, of the entire Service Processor Management
279 Interface Table. */
280 { 32, "length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
281 /* 5 */
282 { 8, "revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
283 /* Entire table must sum to zero. */
284 { 8, "checksum", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
285 /* OEM ID. Per ACPI specification. An OEM-supplied string that
286 identifies the OEM. */
287 { 48, "oemid", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
288 /* For the Service Processor Management Interface Table,
289 the table ID is the manufacturer model ID
290 (assigned by the OEM identified by "OEM ID"). */
291 { 64, "oem_table_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
292 /* OEM revision of Service Processor Management Interface
293 Table for supplied the given OEM Table ID. Per ACPI, this is
294 "An OEM-supplied revision number. Larger numbers are
295 assumed to be newer revisions." */
296 { 32, "oem_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
297 /* Vendor ID of utility that created the table. For the tables
298 containing Definition Blocks, this is the ID for the ASL
299 Compiler. */
300 { 32, "creator_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
301 /* Revision of utility that created the table. For the tables
302 containing Definition Blocks, this is the revision
303 for the ASL Compiler. */
304 { 32, "creator_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
305 /* Indicates the type of IPMI interface:
306 0 Reserved
307 1 Keyboard Controller Style (KCS)
308 2 Server Management Interface Chip (SMIC)
309 3 Block Transfer (BT)
310 4 SMBus System Interface (SSIF)
311 5-255 Reserved */
312 { 8, "interface_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
313 /* This field must always be 01h to be compatible with any
314 software that implements previous
315 versions of this spec. */
316 { 8, "ipmi_legacy", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
317 /* Identifies the IPMI specification revision,
318 in BCD format, to which the interface
319 was designed. The first byte holds the
320 most significant digits, while second byte holds
321 the least significant digits of the revision,
322 e.g. a value of 0x0150 indicates the interface is
323 compatible with IPMI version v1.5. */
324 /* {16, "specification_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED}, */
325 { 8, "specification_revision.major", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
326 { 8, "specification_revision.minor", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
327 /* Interrupt type(s) used by
328 the interface:
329 [0] - SCI triggered through GPE
330 (use 0b for SSIF)
331 0 = not supported
332 1 = supported */
333 { 1, "interrupt_type.sci_triggered_thru_gpe", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
334 /* [1] - I/O APIC/SAPIC interrupt
335 (Global System Interrupt) */
336 { 1, "interrupt_type.io_apic_sapic_interrupt", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
337 /* [7:2] - Reserved (must be 0) */
338 { 6, "interrupt_type.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
339 /* The bit assignment of the SCI interrupt within the GPEx_STS
340 register of a GPE described if the FADT that the interface
341 triggers. (Note: This field is valid only if Bit[0] of the Interrupt
342 Type field is set. Otherwise set to 00h.) */
343 { 8, "gpe", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
344 /* 00h */
345 { 8, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
346 /* [0] - PCI Device Flag. For PCI IPMI devices,
347 this bit is set. For non-PCI devices, this bit is cleared.
348 When this bit is cleared, the PCI Segment Group, Bus,
349 Device and Function Number fields combined corresponds
350 to the ACPI _UID value of the device whose _HID or _CID
351 contains IPI0001 plug and play ID.
352 _UID must be an integer. Byte 60 contains the least
353 significant byte of the _UID value. Set to 0b for SSIF. */
354 { 1, "pci_device_flag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
355 /* [7:1] - Reserved */
356 { 7, "pci_device_flag.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
357 /* The I/O APIC or I/O SAPIC Global System
358 Interrupt used by the interface.
359 (Note: This field is valid only if Bit[1] of the
360 Interrupt Type field is set.
361 Otherwise set to 00h.) */
362 { 32, "global_system_interrupt", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
363 /* The base address of the interface register
364 set described using the Generic Address Structure
365 (GAS, See [ACPI 2.0] for the
366 definition). The Address_Space_ID field in
367 the GAS can only be of the value of 0 (System Memory),
368 1 (System IO), and 4 (SMBus).
369 All other values are not permitted.
370 For SSIF:
371 The Address_Space_ID = 4 and the address field of the GAS
372 holds the 7-bit slave address of the BMC on the host SMBus
373 in the least significant byte. Note that the slave address is
374 stored with the 7-bit slave address in the least
375 significant 7-
376 bits of the byte, and the most significant
377 bit of the byte set to
378 0b.
379 Register_Bit_Width = 0
380 Register_Bit_Offset = 0
381 Address_Size field = 1 (Byte access)
382 Address = 7-bit SMBus address of BMC
383 SSIF */
384 /* {96, "base_address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED}, */
385 /* Address space where
386 struct or register
387 exists. */
388 { 8, "base_address.address_space_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
389 /* Size in bits of given
390 register */
391 { 8, "base_address.register_bit_width", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
392 /* Bit offset within the
393 register */
394 { 8, "base_address.register_bit_offset", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
395 /* field = 1 (byte
396 access) */
397 { 8, "base_address.address_size", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
398 /* SMBus address of BMC
399 SSIF */
400 { 7, "base_address.address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
401 /* Reserved */
402 { 57, "base_address.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
403 /* for IPMI cards not located on PCI */
404 { 32, "uid", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
405 /* This field must always be null (0x00) to be compatible with
406 any software that implements previous versions of this spec.
407 This field is a deprecated "SPMI ID Field". Implementations
408 based on pre-IPMI v2.0 versions of SPMI may contain a null-
409 terminated string here. */
410 { 8, "reserved2", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
411 { 0, "", 0}
412 };
413
414 fiid_template_t tmpl_acpi_spmi_table_descriptor_pci_ipmi =
415 {
416 /* `SPMI'. Signature for the Service Processor Management
417 Interface Table. */
418 { 32, "signature", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
419 /* Length, in bytes, of the entire Service Processor Management
420 Interface Table. */
421 { 32, "length", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
422 /* 5 */
423 { 8, "revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
424 /* Entire table must sum to zero. */
425 { 8, "checksum", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
426 /* OEM ID. Per ACPI specification. An OEM-supplied string that
427 identifies the OEM. */
428 { 48, "oemid", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
429 /* For the Service Processor Management Interface Table,
430 the table ID is the manufacturer model ID
431 (assigned by the OEM identified by "OEM ID"). */
432 { 64, "oem_table_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
433 /* OEM revision of Service Processor Management Interface
434 Table for supplied the given OEM Table ID. Per ACPI, this is
435 "An OEM-supplied revision number. Larger numbers are
436 assumed to be newer revisions." */
437 { 32, "oem_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
438 /* Vendor ID of utility that created the table. For the tables
439 containing Definition Blocks, this is the ID for the ASL
440 Compiler. */
441 { 32, "creator_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
442 /* Revision of utility that created the table. For the tables
443 containing Definition Blocks, this is the revision
444 for the ASL Compiler. */
445 { 32, "creator_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
446 /* Indicates the type of IPMI interface:
447 0 Reserved
448 1 Keyboard Controller Style (KCS)
449 2 Server Management Interface Chip (SMIC)
450 3 Block Transfer (BT)
451 4 SMBus System Interface (SSIF)
452 5-255 Reserved */
453 { 8, "interface_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
454 /* This field must always be 01h to be compatible with any
455 software that implements previous
456 versions of this spec. */
457 { 8, "ipmi_legacy", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
458 /* Identifies the IPMI specification revision,
459 in BCD format, to which the interface
460 was designed. The first byte holds the
461 most significant digits, while second byte holds
462 the least significant digits of the revision,
463 e.g. a value of 0x0150 indicates the interface is
464 compatible with IPMI version v1.5. */
465 /* {16, "specification_revision", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED}, */
466 { 8, "specification_revision.major", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
467 { 8, "specification_revision.minor", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
468 /* Interrupt type(s) used by
469 the interface:
470 [0] - SCI triggered through GPE
471 (use 0b for SSIF)
472 0 = not supported
473 1 = supported */
474 { 1, "interrupt_type.sci_triggered_thru_gpe", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
475 /* [1] - I/O APIC/SAPIC interrupt
476 (Global System Interrupt) */
477 { 1, "interrupt_type.io_apic_sapic_interrupt", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
478 /* [7:2] - Reserved (must be 0) */
479 { 6, "interrupt_type.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
480 /* The bit assignment of the SCI interrupt within the GPEx_STS
481 register of a GPE described if the FADT that the interface
482 triggers. (Note: This field is valid only if Bit[0] of the Interrupt
483 Type field is set. Otherwise set to 00h.) */
484 { 8, "gpe", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
485 /* 00h */
486 { 8, "reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
487 /* [0] - PCI Device Flag. For PCI IPMI devices,
488 this bit is set. For non-PCI devices, this bit is cleared.
489 When this bit is cleared, the PCI Segment Group, Bus,
490 Device and Function Number fields combined corresponds
491 to the ACPI _UID value of the device whose _HID or _CID
492 contains IPI0001 plug and play ID.
493 _UID must be an integer. Byte 60 contains the least
494 significant byte of the _UID value. Set to 0b for SSIF. */
495 { 1, "pci_device_flag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
496 /* [7:1] - Reserved */
497 { 7, "pci_device_flag.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
498 /* The I/O APIC or I/O SAPIC Global System
499 Interrupt used by the interface.
500 (Note: This field is valid only if Bit[1] of the
501 Interrupt Type field is set.
502 Otherwise set to 00h.) */
503 { 32, "global_system_interrupt", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
504 /* The base address of the interface register
505 set described using the Generic Address Structure
506 (GAS, See [ACPI 2.0] for the
507 definition). The Address_Space_ID field in
508 the GAS can only be of the value of 0 (System Memory),
509 1 (System IO), and 4 (SMBus).
510 All other values are not permitted.
511 For SSIF:
512 The Address_Space_ID = 4 and the address field of the GAS
513 holds the 7-bit slave address of the BMC on the host SMBus
514 in the least significant byte. Note that the slave address is
515 stored with the 7-bit slave address in the least
516 significant 7-
517 bits of the byte, and the most significant
518 bit of the byte set to
519 0b.
520 Register_Bit_Width = 0
521 Register_Bit_Offset = 0
522 Address_Size field = 1 (Byte access)
523 Address = 7-bit SMBus address of BMC SSIF */
524 /* {96, "base_address"} */
525 /* Address space where
526 struct or register
527 exists. */
528 { 8, "base_address.address_space_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
529 /* Size in bits of given
530 register */
531 { 8, "base_address.register_bit_width", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
532 /* Bit offset within the
533 register */
534 { 8, "base_address.register_bit_offset", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
535 /* Must be 0 */
536 { 8, "base_address.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
537 /* 64-bit address of
538 struct or register */
539 { 64, "base_address.address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
540 /* PCI Segment Group Number,
541 if the IPMI device is a PCI
542 device. Otherwise, this field is byte 1 of a UID.
543 See description for PCI Device Flag, above. */
544 { 8, "pci_segment_group_number", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
545 /* PCI Bus Number, if the IPMI device is a PCI device.
546 Otherwise, this field is byte 2 of a UID.
547 See description for PCI Device Flag, above. */
548 { 8, "pci_bus_number", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
549 /* PCI Device fields or byte 3 of a UID. Per PCI Device Flag,
550 above.
551 For PCI Device Flag = 1b:
552 [4:0] - PCI Device Number: The PCI device number if the
553 IPMI device is a PCI device.
554 For PCI Device Flag = 0b:
555 [7:0] - byte 3 of UID */
556 { 4, "pci_device_number", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
557 /* [7:5] - Reserved */
558 { 4, "pci_device_number.reserved", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
559 /* PCI Device fields or byte 4 of a UID.
560 Per PCI Device Flag, above.
561 For PCI Device Flag = 1b:
562 [2:0] - PCI Function Number: The PCI function number if
563 the IPMI device is a PCI device. */
564 { 3, "pci_function_number", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
565 /* [5:3] - Reserved */
566 { 3, "pci_function_number.reserved1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
567 /* [6] - Interrupt Flag:
568 0b = interrupt not supported
569 1b = interrupt supported */
570 { 1, "pci_function_number.interrupt_flag", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
571 /* [7] - Reserved
572 For PCI Device Flag = 0b:
573 [7:0] - byte 4 of UID */
574 { 1, "pci_function_number.reserved2", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
575 /* This field must always be null (0x00) to be compatible with
576 any software that implements previous versions of this spec.
577 This field is a deprecated "SPMI ID Field". Implementations
578 based on pre-IPMI v2.0 versions of SPMI may contain a null-
579 terminated string here. */
580 { 8, "reserved2", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
581 { 0, "", 0}
582 };
583
584 static uint8_t _ipmi_acpi_table_checksum (ipmi_locate_ctx_t ctx,
585 uint8_t *buffer,
586 size_t len);
587 static int _ipmi_acpi_get_rsdp (ipmi_locate_ctx_t ctx,
588 uint64_t rsdp_window_base_address,
589 size_t rsdp_window_size,
590 fiid_obj_t obj_acpi_rsdp_descriptor);
591 static int _ipmi_acpi_get_table (ipmi_locate_ctx_t ctx,
592 uint64_t table_address,
593 char *signature,
594 uint8_t **acpi_table,
595 uint32_t *acpi_table_length);
596 static int _ipmi_acpi_get_table_dev_mem (ipmi_locate_ctx_t ctx,
597 char *signature,
598 unsigned int table_instance,
599 uint8_t **acpi_table,
600 uint32_t *acpi_table_length);
601 static int _ipmi_acpi_get_table_sysfs (ipmi_locate_ctx_t ctx,
602 char *signature,
603 unsigned int table_instance,
604 uint8_t **acpi_table,
605 uint32_t *acpi_table_length);
606 static int _ipmi_acpi_get_firmware_table (ipmi_locate_ctx_t ctx,
607 char *signature,
608 unsigned int table_instance,
609 uint8_t **sign_table_data,
610 uint32_t *sign_table_data_length);
611 static int _ipmi_acpi_get_spmi_table (ipmi_locate_ctx_t ctx,
612 uint8_t interface_type,
613 fiid_obj_t obj_acpi_spmi_table_descriptor);
614
615 #define IPMI_INTERFACE_COUNT 5
616
617 static uint64_t physical_memory_size = 0;
618
619 static int
_ipmi_physical_address_valid(ipmi_locate_ctx_t ctx,uint64_t physical_address,size_t length)620 _ipmi_physical_address_valid (ipmi_locate_ctx_t ctx,
621 uint64_t physical_address,
622 size_t length)
623 {
624 assert (ctx);
625 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
626
627 /* achu: Some buggy kernels will crash the system if the physical
628 * address is bad. Yes, I know it's the kernel's fault, but we have
629 * to do our best to get around it. We do so by making sure the
630 * physical address is legit.
631 */
632 #if defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
633 if (!physical_memory_size)
634 {
635 long pagesize, physical_pages;
636
637 if ((pagesize = sysconf (_SC_PAGESIZE)) < 0)
638 {
639 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
640 return (-1);
641 }
642 if ((physical_pages = sysconf (_SC_PHYS_PAGES)) < 0)
643 {
644 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
645 return (-1);
646 }
647
648 physical_memory_size = pagesize * physical_pages;
649 }
650
651 if (physical_address < physical_memory_size
652 && (physical_address + length) > physical_address
653 && (physical_address + length) < physical_memory_size)
654 return (1);
655 else
656 return (0);
657 #else /* !(_SC_PAGESIZE && _SC_PHYS_PAGES) */
658 /* achu: For now we return 1. Later we can maybe read /dev/meminfo
659 * or something.
660 */
661 return (1);
662 #endif /* !(_SC_PAGESIZE && _SC_PHYS_PAGES) */
663 }
664
665 /*******************************************************************************
666 *
667 * FUNCTION:
668 * _ipmi_acpi_table_checksum
669 *
670 * PARAMETERS:
671 * buffer - Buffer to checksum
672 * length - Size of the buffer
673 *
674 * RETURNS:
675 * 8 bit checksum of buffer. NON-ZERO = checksum failed.
676 *
677 * DESCRIPTION:
678 * Computes an 8 bit checksum of the buffer(length) and returns it.
679 *
680 ******************************************************************************/
681 static uint8_t
_ipmi_acpi_table_checksum(ipmi_locate_ctx_t ctx,uint8_t * buffer,size_t len)682 _ipmi_acpi_table_checksum (ipmi_locate_ctx_t ctx,
683 uint8_t *buffer,
684 size_t len)
685 {
686 size_t i = 0;
687 uint8_t sum = 0;
688
689 assert (ctx);
690 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
691 assert (buffer);
692
693 for (i = 0; i < len; i++)
694 sum += buffer[i];
695
696 return (sum);
697 }
698
699 static int
_ipmi_ioremap(ipmi_locate_ctx_t ctx,uint64_t physical_address,size_t physical_address_len,void ** virtual_address,void ** mapped_address,size_t * mapped_address_len)700 _ipmi_ioremap (ipmi_locate_ctx_t ctx,
701 uint64_t physical_address,
702 size_t physical_address_len,
703 void **virtual_address,
704 void **mapped_address,
705 size_t *mapped_address_len)
706 {
707 uint64_t startaddress;
708 uint32_t pad;
709 int mem_fd = -1;
710 int rv = -1;
711
712 assert (ctx);
713 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
714 assert (physical_address_len);
715 assert (virtual_address);
716 assert (mapped_address);
717 assert (mapped_address_len);
718
719 if (!_ipmi_physical_address_valid (ctx,
720 physical_address,
721 physical_address_len))
722 return (-1);
723
724 if ((mem_fd = open ("/dev/mem",
725 O_RDONLY|O_SYNC)) < 0)
726 {
727 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
728 goto cleanup;
729 }
730
731 /* XXX: what is the error return for getpagesize??? */
732 pad = physical_address % getpagesize ();
733 startaddress = physical_address - pad;
734 *mapped_address_len = physical_address_len + pad;
735
736 if ((*mapped_address = mmap (NULL,
737 *mapped_address_len,
738 PROT_READ,
739 MAP_PRIVATE,
740 mem_fd,
741 startaddress)) == MAP_FAILED)
742 {
743 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
744 goto cleanup;
745 }
746
747 *virtual_address = (*mapped_address) + pad;
748 rv = 0;
749 cleanup:
750 /* ignore potential error, cleanup path */
751 close (mem_fd);
752 return (rv);
753 }
754
755 static void
_ipmi_iounmap(ipmi_locate_ctx_t ctx,void * mapped_address,size_t mapped_address_len)756 _ipmi_iounmap (ipmi_locate_ctx_t ctx,
757 void *mapped_address,
758 size_t mapped_address_len)
759 {
760 assert (ctx);
761 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
762
763 /* ignore potential error, void return func */
764 munmap (mapped_address, mapped_address_len);
765 }
766
767 static int
_ipmi_get_physical_mem_data(ipmi_locate_ctx_t ctx,uint64_t physical_address,size_t length,uint8_t * data)768 _ipmi_get_physical_mem_data (ipmi_locate_ctx_t ctx,
769 uint64_t physical_address,
770 size_t length,
771 uint8_t *data)
772 {
773 void *virtual_address = NULL;
774 void *mapped_address = NULL;
775 size_t mapped_address_len = 0;
776
777 assert (ctx);
778 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
779 assert (data);
780
781 if (_ipmi_ioremap (ctx,
782 physical_address,
783 length,
784 &virtual_address,
785 &mapped_address,
786 &mapped_address_len) < 0)
787 return (-1);
788
789 memcpy (data, virtual_address, length);
790
791 _ipmi_iounmap (ctx, mapped_address, mapped_address_len);
792
793 return (0);
794 }
795
796 /*******************************************************************************
797 *
798 * FUNCTION:
799 * _ipmi_acpi_get_rsdp
800 *
801 * PARAMETERS:
802 * rsdp_window_base_address - Starting pointer for search
803 * rsdp_window_wize - Maximum length to search
804 * obj_acpi_rsdp_descriptor - Initialized rsdp descriptor object
805 *
806 * RETURN:
807 * A return value of 0 means success. RSDP descriptor is returned
808 * through obj_acpi_rsdp_descriptor parameter.
809 *
810 * DESCRIPTION:
811 * Search a block of memory for the RSDP signature.
812 *
813 * NOTE:
814 * The RSDP must be either in the first 1_k of the Extended BIOS
815 * Data Area or between E0000 and FFFFF (ACPI 1.0 section 5.2.2;
816 * assertion #421).
817 *
818 ******************************************************************************/
819 static int
_ipmi_acpi_get_rsdp(ipmi_locate_ctx_t ctx,uint64_t rsdp_window_base_address,size_t rsdp_window_size,fiid_obj_t obj_acpi_rsdp_descriptor)820 _ipmi_acpi_get_rsdp (ipmi_locate_ctx_t ctx,
821 uint64_t rsdp_window_base_address,
822 size_t rsdp_window_size,
823 fiid_obj_t obj_acpi_rsdp_descriptor)
824 {
825 uint8_t *memdata = NULL;
826 int acpi_rsdp_descriptor_len;
827 size_t i;
828 int rv = -1;
829
830 assert (ctx);
831 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
832 assert (fiid_obj_valid (obj_acpi_rsdp_descriptor));
833 assert (fiid_obj_template_compare (obj_acpi_rsdp_descriptor, tmpl_acpi_rsdp_descriptor) == 1);
834
835 if (!(memdata = malloc (rsdp_window_size)))
836 {
837 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
838 goto cleanup;
839 }
840
841 if ((acpi_rsdp_descriptor_len = fiid_template_len_bytes (tmpl_acpi_rsdp_descriptor)) < 0)
842 {
843 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
844 goto cleanup;
845 }
846
847 if (_ipmi_get_physical_mem_data (ctx,
848 rsdp_window_base_address,
849 rsdp_window_size,
850 memdata) < 0)
851 goto cleanup;
852
853 /* Search from given start address for the requested length */
854 for (i = 0; i < rsdp_window_size; i += IPMI_ACPI_RSDP_SCAN_STEP)
855 {
856 /* check RSDP signature */
857 if (strncmp ((char *)&memdata[i],
858 IPMI_ACPI_RSDP_SIG,
859 strlen (IPMI_ACPI_RSDP_SIG)) != 0)
860 continue;
861
862 /* now check the checksum */
863 if (!_ipmi_acpi_table_checksum (ctx,
864 &memdata[i],
865 IPMI_ACPI_RSDP_CHECKSUM_LENGTH))
866 {
867 if (fiid_obj_set_all (obj_acpi_rsdp_descriptor,
868 &memdata[i],
869 acpi_rsdp_descriptor_len) < 0)
870 {
871 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_rsdp_descriptor);
872 goto cleanup;
873 }
874
875 /* check this RSDP has RSDT/XSDT */
876 {
877 uint64_t val;
878 uint8_t revision;
879 uint64_t rsdt_xsdt_address;
880 char *rsdt_xsdt_signature;
881 uint8_t *rsdt_xsdt_table = NULL;
882 uint32_t rsdt_xsdt_table_length;
883
884 if (FIID_OBJ_GET (obj_acpi_rsdp_descriptor,
885 "revision",
886 &val) < 0)
887 {
888 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_rsdp_descriptor);
889 goto cleanup;
890 }
891
892 revision = val;
893 if (revision < 2)
894 {
895 if (FIID_OBJ_GET (obj_acpi_rsdp_descriptor,
896 "rsdt_physical_address",
897 &rsdt_xsdt_address) < 0)
898 {
899 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_rsdp_descriptor);
900 goto cleanup;
901 }
902
903 rsdt_xsdt_signature = IPMI_ACPI_RSDT_SIG;
904 }
905 else
906 {
907 if (FIID_OBJ_GET (obj_acpi_rsdp_descriptor,
908 "xsdt_physical_address",
909 &rsdt_xsdt_address) < 0)
910 {
911 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_rsdp_descriptor);
912 goto cleanup;
913 }
914
915 rsdt_xsdt_signature = IPMI_ACPI_XSDT_SIG;
916 }
917
918 /* achu: logic of code indicates should check for == 0, not < 0 */
919 if (_ipmi_acpi_get_table (ctx,
920 rsdt_xsdt_address,
921 rsdt_xsdt_signature,
922 &rsdt_xsdt_table,
923 &rsdt_xsdt_table_length) == 0)
924 {
925 /* we found RSDT/XSDT */
926 free (rsdt_xsdt_table);
927 rv = 0;
928 goto cleanup;
929 }
930 free (rsdt_xsdt_table);
931
932 /* This is special case because of EFI */
933 if (FIID_OBJ_GET (obj_acpi_rsdp_descriptor,
934 "rsdt_physical_address",
935 &rsdt_xsdt_address) < 0)
936 {
937 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_rsdp_descriptor);
938 goto cleanup;
939 }
940
941 free (memdata);
942 if (!(memdata = malloc (acpi_rsdp_descriptor_len)))
943 {
944 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_OUT_OF_MEMORY);
945 goto cleanup;
946 }
947
948 if (_ipmi_get_physical_mem_data (ctx,
949 rsdt_xsdt_address,
950 acpi_rsdp_descriptor_len,
951 memdata) < 0)
952 goto cleanup;
953
954 /* check RSDP signature */
955 if (strncmp ((char *)memdata,
956 IPMI_ACPI_RSDP_SIG,
957 strlen (IPMI_ACPI_RSDP_SIG)))
958 {
959 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
960 goto cleanup;
961 }
962
963 /* now check the checksum */
964 if (_ipmi_acpi_table_checksum (ctx,
965 memdata,
966 IPMI_ACPI_RSDP_CHECKSUM_LENGTH) != 0)
967 {
968 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
969 goto cleanup;
970 }
971
972 /* we found another RSDP */
973 memcpy (obj_acpi_rsdp_descriptor, memdata, acpi_rsdp_descriptor_len);
974 }
975
976 rv = 0;
977 goto cleanup;
978 }
979 }
980
981 cleanup:
982 free (memdata);
983 return (rv);
984 }
985
986 /*******************************************************************************
987 *
988 * FUNCTION:
989 * _ipmi_acpi_get_table
990 *
991 * PARAMETERS:
992 * table_address - ACPI table physical address
993 * signature - signature of the table
994 * acpi_table - ACPI table in malloc'ed memory
995 * acpi_table_length - ACPI table length
996 *
997 * RETURN:
998 * A return value of 0 means success. ACPI table (including header) is
999 * returned through acpi_table parameter.
1000 *
1001 * DESCRIPTION:
1002 * Retrieve any ACPI table (including header) pointed by table address.
1003 *
1004 ******************************************************************************/
1005 static int
_ipmi_acpi_get_table(ipmi_locate_ctx_t ctx,uint64_t table_address,char * signature,uint8_t ** acpi_table,uint32_t * acpi_table_length)1006 _ipmi_acpi_get_table (ipmi_locate_ctx_t ctx,
1007 uint64_t table_address,
1008 char *signature,
1009 uint8_t **acpi_table,
1010 uint32_t *acpi_table_length)
1011 {
1012 uint64_t val;
1013
1014 uint8_t table_signature_length;
1015 char *table_signature = NULL;
1016
1017 fiid_obj_t obj_acpi_table_hdr = NULL;
1018 uint8_t *acpi_table_buf = NULL;
1019 uint32_t table_length = 0;
1020 int acpi_table_hdr_length;
1021 uint8_t *table = NULL;
1022 int len;
1023 int rv = -1;
1024
1025 assert (ctx);
1026 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
1027 assert (signature);
1028 assert (acpi_table);
1029 assert (acpi_table_length);
1030
1031 *acpi_table = NULL;
1032
1033 if ((len = fiid_template_field_len_bytes (tmpl_acpi_table_hdr, "signature")) < 0)
1034 {
1035 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1036 goto cleanup;
1037 }
1038
1039 table_signature_length = len;
1040 if (!(table_signature = malloc (table_signature_length + 1)))
1041 {
1042 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1043 goto cleanup;
1044 }
1045 memset (table_signature, '\0', table_signature_length + 1);
1046
1047 if ((acpi_table_hdr_length = fiid_template_len_bytes (tmpl_acpi_table_hdr)) < 0)
1048 {
1049 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1050 goto cleanup;
1051 }
1052
1053 if (!(obj_acpi_table_hdr = fiid_obj_create (tmpl_acpi_table_hdr)))
1054 {
1055 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1056 goto cleanup;
1057 }
1058
1059 if (!(acpi_table_buf = malloc (acpi_table_hdr_length)))
1060 {
1061 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1062 goto cleanup;
1063 }
1064
1065 if (_ipmi_get_physical_mem_data (ctx,
1066 table_address,
1067 acpi_table_hdr_length,
1068 acpi_table_buf) < 0)
1069 goto cleanup;
1070
1071 if (fiid_obj_set_all (obj_acpi_table_hdr,
1072 acpi_table_buf,
1073 acpi_table_hdr_length) < 0)
1074 {
1075 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_table_hdr);
1076 goto cleanup;
1077 }
1078
1079 if (fiid_obj_get_data (obj_acpi_table_hdr,
1080 "signature",
1081 table_signature,
1082 table_signature_length) < 0)
1083 {
1084 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_table_hdr);
1085 goto cleanup;
1086 }
1087
1088 if (strcmp (table_signature, signature))
1089 {
1090 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1091 goto cleanup;
1092 }
1093
1094 if (FIID_OBJ_GET (obj_acpi_table_hdr,
1095 "length",
1096 &val) < 0)
1097 {
1098 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_table_hdr);
1099 goto cleanup;
1100 }
1101 table_length = val;
1102
1103 if (!(table = malloc (table_length)))
1104 {
1105 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1106 goto cleanup;
1107 }
1108 memset (table, '\0', table_length);
1109
1110 if (_ipmi_get_physical_mem_data (ctx,
1111 table_address,
1112 table_length,
1113 table) < 0)
1114 goto cleanup;
1115
1116 if (_ipmi_acpi_table_checksum (ctx,
1117 table,
1118 table_length) != 0)
1119 {
1120 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1121 goto cleanup;
1122 }
1123
1124 if (!(*acpi_table = malloc (table_length)))
1125 {
1126 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_OUT_OF_MEMORY);
1127 goto cleanup;
1128 }
1129 memcpy (*acpi_table, table, table_length);
1130 *acpi_table_length = table_length;
1131
1132 rv = 0;
1133 cleanup:
1134 free (table_signature);
1135 free (acpi_table_buf);
1136 free (table);
1137 fiid_obj_destroy (obj_acpi_table_hdr);
1138 return (rv);
1139 }
1140
1141 /*******************************************************************************
1142 *
1143 * FUNCTION:
1144 * _ipmi_acpi_get_table_sysfs
1145 *
1146 * PARAMETERS:
1147 * signature - signature of the table
1148 * table_instance - Which instance of the firmware table
1149 * acpi_table - ACPI table in malloc'ed memory
1150 * acpi_table_length - ACPI table length
1151 *
1152 * RETURN:
1153 * A return value of 0 means success. ACPI table (including header) is
1154 * returned through acpi_table parameter.
1155 *
1156 * DESCRIPTION:
1157 * Retrieve any ACPI table (including header) from sysfs.
1158 *
1159 ******************************************************************************/
1160 static int
_ipmi_acpi_get_table_sysfs(ipmi_locate_ctx_t ctx,char * signature,unsigned int table_instance,uint8_t ** acpi_table,uint32_t * acpi_table_length)1161 _ipmi_acpi_get_table_sysfs (ipmi_locate_ctx_t ctx,
1162 char *signature,
1163 unsigned int table_instance,
1164 uint8_t **acpi_table,
1165 uint32_t *acpi_table_length)
1166 {
1167 int sysfs_acpi_fd = -1;
1168 int rv = -1;
1169 static char const sysfs_fw_acpi_tables[] = "/sys/firmware/acpi/tables";
1170 char *sysfs_path;
1171 int instance_length;
1172 int sysfs_path_length;
1173 uint8_t *acpi_table_buf = NULL;
1174
1175 assert (ctx);
1176 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
1177 assert (signature);
1178 assert (table_instance >= 0);
1179 assert (acpi_table);
1180 assert (acpi_table_length);
1181
1182 *acpi_table = NULL;
1183
1184 instance_length = (table_instance + 1) / 10 + 1;
1185 sysfs_path_length = strlen (sysfs_fw_acpi_tables) + strlen(signature) + \
1186 instance_length + 2;
1187
1188 if (!(sysfs_path = malloc (sysfs_path_length)))
1189 {
1190 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_OUT_OF_MEMORY);
1191 return (-1);
1192 }
1193
1194 snprintf (sysfs_path, sysfs_path_length, "%s/%s%d",
1195 sysfs_fw_acpi_tables, signature, table_instance + 1);
1196 if ((sysfs_acpi_fd = open (sysfs_path, O_RDONLY)) < 0)
1197 {
1198 if (table_instance > 0)
1199 goto cleanup;
1200 /* If there is only 1 instance of a table on the system, the sysfs
1201 file will be the same as the signature, (e.g.
1202 /sys/firmware/acpi/tables/SPMI). If there are multiple instances
1203 of the same table, they will have the instance # as a suffix (e.g.:
1204 /sys/firmware/acpi/tables/SPMI1 & /sys/firmware/acpi/tables/SPMI2).
1205 So, for table_instance == 0, we need to try both */
1206 snprintf (sysfs_path, sysfs_path_length, "%s/%s",
1207 sysfs_fw_acpi_tables, signature);
1208 if ((sysfs_acpi_fd = open (sysfs_path, O_RDONLY)) < 0)
1209 goto cleanup;
1210 }
1211 if ((*acpi_table_length = lseek (sysfs_acpi_fd, 0, SEEK_END)) == -1)
1212 {
1213 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1214 goto cleanup;
1215 }
1216 if ((lseek (sysfs_acpi_fd, 0, SEEK_SET)) == -1)
1217 {
1218 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1219 goto cleanup;
1220 }
1221 if (!(acpi_table_buf = malloc (*acpi_table_length)))
1222 {
1223 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_OUT_OF_MEMORY);
1224 goto cleanup;
1225 }
1226 if ((read (sysfs_acpi_fd, acpi_table_buf, *acpi_table_length)) !=
1227 *acpi_table_length)
1228 {
1229 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1230 goto cleanup;
1231 }
1232
1233 *acpi_table = acpi_table_buf;
1234 rv = 0;
1235 cleanup:
1236 close (sysfs_acpi_fd);
1237 return rv;
1238 }
1239
1240 /*******************************************************************************
1241 *
1242 * FUNCTION:
1243 * _ipmi_acpi_get_firmware_table_dev_mem
1244 *
1245 * PARAMETERS:
1246 * signature - ACPI signature for firmware table header
1247 * table_instance - Which instance of the firmware table
1248 * acpi_table - Initialized with malloc'ed ACPI firmware table data
1249 * acpi_table_length - ACPI table DATA length
1250 *
1251 * RETURN:
1252 * return (0) for success. ACPI table (including header) is
1253 * returned through the signed_table_data parameter.
1254 *
1255 * DESCRIPTION:
1256 * Top level call for any ACPI firmware table by table signature string.
1257 * It gets table header and data from RSDT/XSDT.
1258 *
1259 ******************************************************************************/
1260 static int
_ipmi_acpi_get_table_dev_mem(ipmi_locate_ctx_t ctx,char * signature,unsigned int table_instance,uint8_t ** acpi_table,uint32_t * acpi_table_length)1261 _ipmi_acpi_get_table_dev_mem (ipmi_locate_ctx_t ctx,
1262 char *signature,
1263 unsigned int table_instance,
1264 uint8_t **acpi_table,
1265 uint32_t *acpi_table_length)
1266 {
1267 uint64_t val;
1268
1269 int acpi_table_hdr_length;
1270 int acpi_rsdp_descriptor_length;
1271
1272 fiid_obj_t obj_acpi_rsdp_descriptor = NULL;
1273 uint64_t rsdt_xsdt_address;
1274 char *rsdt_xsdt_signature;
1275 uint8_t revision;
1276
1277 uint8_t *rsdt_xsdt_table = NULL;
1278 uint32_t rsdt_xsdt_table_length;
1279 uint8_t *rsdt_xsdt_table_data;
1280 uint32_t rsdt_xsdt_table_data_length;
1281 unsigned int acpi_table_count;
1282
1283 fiid_obj_t obj_table = NULL;
1284 uint64_t table_address;
1285 unsigned int signature_table_count;
1286 unsigned int i;
1287 int rv = -1;
1288 fiid_template_t tmpl_table_address_32 =
1289 {
1290 { 32, "table_address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
1291 { 0, "", 0}
1292 };
1293 fiid_template_t tmpl_table_address_64 =
1294 {
1295 { 64, "table_address", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
1296 { 0, "", 0}
1297 };
1298
1299 #if defined(__arm__) || defined (__aarch64__)
1300 return (-1);
1301 #endif
1302 assert (ctx);
1303 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
1304 assert (signature);
1305 assert (acpi_table);
1306 assert (acpi_table_length);
1307
1308 *acpi_table = NULL;
1309
1310 if ((acpi_table_hdr_length = fiid_template_len_bytes (tmpl_acpi_table_hdr)) < 0)
1311 {
1312 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1313 goto cleanup;
1314 }
1315
1316 if (!(obj_acpi_rsdp_descriptor = fiid_obj_create (tmpl_acpi_rsdp_descriptor)))
1317 {
1318 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1319 goto cleanup;
1320 }
1321
1322 if ((acpi_rsdp_descriptor_length = fiid_template_len_bytes (tmpl_acpi_rsdp_descriptor)) < 0)
1323 {
1324 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1325 goto cleanup;
1326 }
1327
1328 if (_ipmi_acpi_get_rsdp (ctx,
1329 IPMI_ACPI_LO_RSDP_WINDOW_BASE,
1330 IPMI_ACPI_LO_RSDP_WINDOW_SIZE,
1331 obj_acpi_rsdp_descriptor) < 0)
1332 {
1333 if (_ipmi_acpi_get_rsdp (ctx,
1334 IPMI_ACPI_HI_RSDP_WINDOW_BASE,
1335 IPMI_ACPI_HI_RSDP_WINDOW_SIZE,
1336 obj_acpi_rsdp_descriptor) < 0)
1337 goto cleanup;
1338 }
1339
1340 if (FIID_OBJ_GET (obj_acpi_rsdp_descriptor,
1341 "revision",
1342 &val) < 0)
1343 {
1344 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_rsdp_descriptor);
1345 goto cleanup;
1346 }
1347
1348 revision = val;
1349 if (revision < 2)
1350 {
1351 if (FIID_OBJ_GET (obj_acpi_rsdp_descriptor,
1352 "rsdt_physical_address",
1353 &rsdt_xsdt_address) < 0)
1354 {
1355 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_rsdp_descriptor);
1356 goto cleanup;
1357 }
1358 rsdt_xsdt_signature = IPMI_ACPI_RSDT_SIG;
1359 }
1360 else
1361 {
1362 if (FIID_OBJ_GET (obj_acpi_rsdp_descriptor,
1363 "xsdt_physical_address",
1364 &rsdt_xsdt_address) < 0)
1365 {
1366 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_rsdp_descriptor);
1367 goto cleanup;
1368 }
1369 rsdt_xsdt_signature = IPMI_ACPI_XSDT_SIG;
1370 }
1371
1372 if (_ipmi_acpi_get_table (ctx,
1373 rsdt_xsdt_address,
1374 rsdt_xsdt_signature,
1375 &rsdt_xsdt_table,
1376 &rsdt_xsdt_table_length) < 0)
1377 goto cleanup;
1378
1379 rsdt_xsdt_table_data_length = rsdt_xsdt_table_length - acpi_table_hdr_length;
1380 rsdt_xsdt_table_data = (rsdt_xsdt_table + acpi_table_hdr_length);
1381
1382 if (revision < 2)
1383 acpi_table_count = rsdt_xsdt_table_data_length / 4;
1384 else
1385 acpi_table_count = rsdt_xsdt_table_data_length / 8;
1386
1387 acpi_table_length = 0;
1388 for (i = 0, signature_table_count = 0; i < acpi_table_count; i++)
1389 {
1390 fiid_field_t *tmpl_table_address = NULL;
1391 int len_table;
1392
1393 if (revision < 2)
1394 tmpl_table_address = &tmpl_table_address_32[0];
1395 else
1396 tmpl_table_address = &tmpl_table_address_64[0];
1397
1398 if (!(obj_table = fiid_obj_create (tmpl_table_address)))
1399 {
1400 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1401 goto cleanup;
1402 }
1403
1404 if ((len_table = fiid_template_len_bytes (tmpl_table_address)) < 0)
1405 {
1406 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1407 goto cleanup;
1408 }
1409
1410 if (fiid_obj_set_all (obj_table,
1411 (rsdt_xsdt_table_data + (i * 4)),
1412 len_table) < 0)
1413 {
1414 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_table);
1415 goto cleanup;
1416 }
1417
1418 if (FIID_OBJ_GET (obj_table,
1419 "table_address",
1420 &table_address) < 0)
1421 {
1422 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_table);
1423 goto cleanup;
1424 }
1425
1426 fiid_obj_destroy (obj_table);
1427
1428 if (_ipmi_acpi_get_table (ctx,
1429 table_address,
1430 signature,
1431 acpi_table,
1432 acpi_table_length) < 0)
1433 continue;
1434
1435 signature_table_count++;
1436 if (signature_table_count == table_instance)
1437 break;
1438
1439 free (acpi_table);
1440 acpi_table = NULL;
1441 acpi_table_length = 0;
1442 }
1443
1444 if (!acpi_table)
1445 {
1446 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1447 goto cleanup;
1448 }
1449
1450 rv = 0;
1451 cleanup:
1452 free (rsdt_xsdt_table);
1453 fiid_obj_destroy (obj_table);
1454 fiid_obj_destroy (obj_acpi_rsdp_descriptor);
1455 return (rv);
1456 }
1457
1458 /*******************************************************************************
1459 *
1460 * FUNCTION:
1461 * _ipmi_acpi_get_firmware_table
1462 *
1463 * PARAMETERS:
1464 * signature - ACPI signature for firmware table header
1465 * table_instance - Which instance of the firmware table
1466 * sign_table_data - Initialized with malloc'ed ACPI firmware table data
1467 * sign_table_data_length - ACPI table DATA length
1468 *
1469 * RETURN:
1470 * return (0) for success. ACPI table (including header) is returned
1471 * through the signed_table_data parameter.
1472 *
1473 * DESCRIPTION:
1474 * Top level call for any ACPI firmware table by table signature string.
1475 *
1476 ******************************************************************************/
1477 static int
_ipmi_acpi_get_firmware_table(ipmi_locate_ctx_t ctx,char * signature,unsigned int table_instance,uint8_t ** sign_table_data,uint32_t * sign_table_data_length)1478 _ipmi_acpi_get_firmware_table (ipmi_locate_ctx_t ctx,
1479 char *signature,
1480 unsigned int table_instance,
1481 uint8_t **sign_table_data,
1482 uint32_t *sign_table_data_length)
1483 {
1484 uint8_t *acpi_table = NULL;
1485 uint32_t acpi_table_length;
1486
1487 int rv = -1;
1488
1489 assert (ctx);
1490 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
1491 assert (signature);
1492 assert (sign_table_data);
1493 assert (sign_table_data_length);
1494
1495 *sign_table_data = NULL;
1496
1497 if ((_ipmi_acpi_get_table_sysfs (ctx, signature, table_instance,
1498 &acpi_table, &acpi_table_length) != 0))
1499 {
1500 if ((_ipmi_acpi_get_table_dev_mem (ctx, signature,
1501 table_instance,
1502 &acpi_table,
1503 &acpi_table_length) != 0))
1504 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1505 goto cleanup;
1506 }
1507
1508 if (!acpi_table)
1509 {
1510 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1511 goto cleanup;
1512 }
1513
1514 *sign_table_data_length = acpi_table_length;
1515 if (!(*sign_table_data = malloc (*sign_table_data_length)))
1516 {
1517 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_OUT_OF_MEMORY);
1518 goto cleanup;
1519 }
1520 memcpy (*sign_table_data, acpi_table, *sign_table_data_length);
1521
1522 rv = 0;
1523 cleanup:
1524 free (acpi_table);
1525 return (rv);
1526 }
1527
1528 /*******************************************************************************
1529 *
1530 * FUNCTION:
1531 * _ipmi_acpi_get_spmi_table
1532 *
1533 * PARAMETERS:
1534 * interface_type - Type of interface to look for (KCS, SSIF, SMIC, BT)
1535 * acpi_table_firmware - Initialized ACPI firmware table
1536 *
1537 * RETURN:
1538 * return (0) for success. ACPI SPMI table (including header) is
1539 * returned through the obj_acpi_spmi_table_descriptor parameter.
1540 *
1541 * DESCRIPTION:
1542 * Get SPMI table for the given interface type.
1543 *
1544 ******************************************************************************/
1545 static int
_ipmi_acpi_get_spmi_table(ipmi_locate_ctx_t ctx,uint8_t interface_type,fiid_obj_t obj_acpi_spmi_table_descriptor)1546 _ipmi_acpi_get_spmi_table (ipmi_locate_ctx_t ctx,
1547 uint8_t interface_type,
1548 fiid_obj_t obj_acpi_spmi_table_descriptor)
1549 {
1550 uint64_t val;
1551 uint8_t table_interface_type;
1552 uint8_t *table_data = NULL;
1553 uint32_t table_data_length = 0;
1554 uint32_t copy_length;
1555 unsigned int instance;
1556 int acpi_spmi_table_descriptor_len;
1557 int rv = -1;
1558
1559 assert (ctx);
1560 assert (ctx->magic == IPMI_LOCATE_CTX_MAGIC);
1561 assert (fiid_obj_valid (obj_acpi_spmi_table_descriptor));
1562 assert (fiid_obj_template_compare (obj_acpi_spmi_table_descriptor, tmpl_acpi_spmi_table_descriptor) == 1);
1563
1564 for (instance = 0; instance < IPMI_INTERFACE_COUNT; instance++)
1565 {
1566 if (_ipmi_acpi_get_firmware_table (ctx,
1567 IPMI_ACPI_SPMI_SIG,
1568 instance,
1569 &table_data,
1570 &table_data_length) < 0)
1571 continue;
1572
1573 #if 0
1574 printf ("__DEBUG__ instance = %d, signature = [%s] found\n",
1575 instance, IPMI_ACPI_SPMI_SIG);
1576 #endif
1577
1578 if ((acpi_spmi_table_descriptor_len = fiid_template_len_bytes (tmpl_acpi_spmi_table_descriptor)) < 0)
1579 {
1580 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1581 goto cleanup;
1582 }
1583
1584 if (acpi_spmi_table_descriptor_len < table_data_length)
1585 copy_length = acpi_spmi_table_descriptor_len;
1586 else
1587 copy_length = table_data_length;
1588
1589 #if 0
1590 if (copy_length != table_data_length)
1591 printf ("_DEBUG_ table_data_length=%d, template_length=%d,"
1592 " tmpl_acpi_spmi_table_descriptor length is too short\n",
1593 table_data_length, acpi_spmi_table_descriptor_len);
1594 #endif
1595
1596 if (fiid_obj_set_all (obj_acpi_spmi_table_descriptor,
1597 table_data,
1598 copy_length) < 0)
1599 {
1600 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1601 goto cleanup;
1602 }
1603
1604 free (table_data);
1605 table_data = NULL;
1606 table_data_length = 0;
1607
1608 if (FIID_OBJ_GET (obj_acpi_spmi_table_descriptor,
1609 "interface_type",
1610 &val) < 0)
1611 {
1612 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1613 goto cleanup;
1614 }
1615
1616 table_interface_type = val;
1617 if (table_interface_type == interface_type)
1618 {
1619 rv = 0;
1620 break;
1621 }
1622 }
1623
1624 cleanup:
1625 free (table_data);
1626 return (rv);
1627 }
1628
1629 int
ipmi_locate_acpi_spmi_get_device_info(ipmi_locate_ctx_t ctx,ipmi_interface_type_t type,struct ipmi_locate_info * info)1630 ipmi_locate_acpi_spmi_get_device_info (ipmi_locate_ctx_t ctx,
1631 ipmi_interface_type_t type,
1632 struct ipmi_locate_info *info)
1633 {
1634 fiid_obj_t obj_acpi_spmi_table_descriptor = NULL;
1635 struct ipmi_locate_info linfo;
1636 uint64_t val;
1637 int rv = -1;
1638
1639 if (!ctx || ctx->magic != IPMI_LOCATE_CTX_MAGIC)
1640 {
1641 ERR_TRACE (ipmi_locate_ctx_errormsg (ctx), ipmi_locate_ctx_errnum (ctx));
1642 return (-1);
1643 }
1644
1645 if (!IPMI_INTERFACE_TYPE_VALID (type) || !info)
1646 {
1647 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_PARAMETERS);
1648 return (-1);
1649 }
1650
1651 memset (&linfo, '\0', sizeof (struct ipmi_locate_info));
1652 linfo.interface_type = type;
1653 if (type == IPMI_INTERFACE_SSIF)
1654 {
1655 strncpy (linfo.driver_device, IPMI_DEFAULT_I2C_DEVICE, IPMI_LOCATE_PATH_MAX);
1656 linfo.driver_device[IPMI_LOCATE_PATH_MAX - 1] = '\0';
1657 }
1658 linfo.locate_driver_type = IPMI_LOCATE_DRIVER_ACPI;
1659
1660 if (!(obj_acpi_spmi_table_descriptor = fiid_obj_create (tmpl_acpi_spmi_table_descriptor)))
1661 {
1662 LOCATE_ERRNO_TO_LOCATE_ERRNUM (ctx, errno);
1663 goto cleanup;
1664 }
1665
1666 if (_ipmi_acpi_get_spmi_table (ctx,
1667 type,
1668 obj_acpi_spmi_table_descriptor) < 0)
1669 goto cleanup;
1670
1671 /* I don't see any reason to perform this check now -- Anand Babu */
1672 /* This field must always be 01h to be compatible with any software
1673 that implements previous versions of this spec. */
1674 #if 0
1675 {
1676 uint8_t ipmi_legacy;
1677
1678 if (FIID_OBJ_GET (obj_acpi_spmi_table_descriptor,
1679 tmpl_acpi_spmi_table_descriptor,
1680 "ipmi_legacy",
1681 &val) < 0)
1682 {
1683 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1684 goto cleanup;
1685 }
1686 ipmi_legacy = val;
1687
1688 if (ipmi_legacy != 1)
1689 {
1690 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1691 goto cleanup;
1692 }
1693 }
1694 #endif
1695
1696 /* IPMI version */
1697 {
1698 uint8_t ipmi_version_major, ipmi_version_minor;
1699
1700 if (FIID_OBJ_GET (obj_acpi_spmi_table_descriptor,
1701 "specification_revision.major",
1702 &val) < 0)
1703 {
1704 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1705 goto cleanup;
1706 }
1707 ipmi_version_major = val;
1708
1709 if (FIID_OBJ_GET (obj_acpi_spmi_table_descriptor,
1710 "specification_revision.minor",
1711 &val) < 0)
1712 {
1713 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1714 goto cleanup;
1715 }
1716 ipmi_version_minor = val;
1717
1718 linfo.ipmi_version_major = ipmi_version_major;
1719 linfo.ipmi_version_minor = ipmi_version_minor;
1720 }
1721
1722 /* Interface type - KCS, SMIC, SSIF, BT */
1723 {
1724 uint8_t interface_type;
1725
1726 if (FIID_OBJ_GET (obj_acpi_spmi_table_descriptor,
1727 "interface_type",
1728 &val) < 0)
1729 {
1730 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1731 goto cleanup;
1732 }
1733 interface_type = val;
1734
1735 if (!IPMI_INTERFACE_TYPE_VALID (interface_type))
1736 {
1737 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1738 goto cleanup;
1739 }
1740
1741 linfo.interface_type = interface_type;
1742 }
1743
1744 /* Address space id (memory mapped, IO mapped, SMBus) and IO base address */
1745 {
1746 uint8_t address_space_id;
1747 uint64_t base_address;
1748
1749 if (FIID_OBJ_GET (obj_acpi_spmi_table_descriptor,
1750 "base_address.address_space_id",
1751 &val) < 0)
1752 {
1753 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1754 goto cleanup;
1755 }
1756 address_space_id = val;
1757
1758 if (FIID_OBJ_GET (obj_acpi_spmi_table_descriptor,
1759 "base_address.address",
1760 &val) < 0)
1761 {
1762 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1763 goto cleanup;
1764 }
1765 base_address = val;
1766
1767 switch (address_space_id)
1768 {
1769 case IPMI_ACPI_ADDRESS_SPACE_ID_SYSTEM_MEMORY:
1770 {
1771 linfo.address_space_id = IPMI_ADDRESS_SPACE_ID_SYSTEM_MEMORY;
1772 linfo.driver_address = base_address;
1773 break;
1774 }
1775 case IPMI_ACPI_ADDRESS_SPACE_ID_SYSTEM_IO:
1776 {
1777 linfo.address_space_id = IPMI_ADDRESS_SPACE_ID_SYSTEM_IO;
1778 linfo.driver_address = base_address;
1779 break;
1780 }
1781 case IPMI_ACPI_ADDRESS_SPACE_ID_SMBUS:
1782 {
1783 linfo.address_space_id = IPMI_ADDRESS_SPACE_ID_SMBUS;
1784 linfo.driver_address = base_address;
1785 break;
1786 }
1787 default:
1788 LOCATE_SET_ERRNUM (ctx, IPMI_LOCATE_ERR_SYSTEM_ERROR);
1789 goto cleanup;
1790 }
1791 }
1792
1793 /* Register spacing */
1794 {
1795 uint8_t register_bit_width;
1796
1797 if (FIID_OBJ_GET (obj_acpi_spmi_table_descriptor,
1798 "base_address.register_bit_width",
1799 &val) < 0)
1800 {
1801 LOCATE_FIID_OBJECT_ERROR_TO_LOCATE_ERRNUM (ctx, obj_acpi_spmi_table_descriptor);
1802 goto cleanup;
1803 }
1804 register_bit_width = val;
1805
1806 linfo.register_spacing = (register_bit_width / 8);
1807 }
1808
1809 memcpy (info, &linfo, sizeof (struct ipmi_locate_info));
1810 rv = 0;
1811 cleanup:
1812 fiid_obj_destroy (obj_acpi_spmi_table_descriptor);
1813 return (rv);
1814 }
1815