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