1# Copyright (C) 2021-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import ctypes
7import copy
8
9import inspectorlib.cdata as cdata
10import inspectorlib.unpack as unpack
11from acpiparser._utils import TableHeader, GAS
12
13_preferred_pm_profile = {
14    0: 'Unspecified',
15    1: 'Desktop',
16    2: 'Mobile',
17    3: 'Workstation',
18    4: 'Enterprise Server',
19    5: 'SOHO Server',
20    6: 'Appliance PC',
21    7: 'Performance Server',
22    8: 'Tablet'
23}
24
25class facp_flags_bits_v1(cdata.Struct):
26    _pack_ = 1
27    _fields_ = [
28        ('wbinvd', ctypes.c_uint32, 1),
29        ('wbinvd_flush', ctypes.c_uint32, 1),
30        ('proc_c1', ctypes.c_uint32, 1),
31        ('p_lvl2_up', ctypes.c_uint32, 1),
32        ('pwr_button', ctypes.c_uint32, 1),
33        ('slp_button', ctypes.c_uint32, 1),
34        ('fix_rtc', ctypes.c_uint32, 1),
35        ('rtc_s4', ctypes.c_uint32, 1),
36        ('tmr_val_ext', ctypes.c_uint32, 1),
37        ('dck_cap', ctypes.c_uint32, 1),
38    ]
39
40class facp_flags_v1(cdata.Union):
41    _pack_ = 1
42    _anonymous_ = ("bits",)
43    _fields_ = [
44        ('data', ctypes.c_uint32),
45        ('bits', facp_flags_bits_v1),
46    ]
47
48class FACP_v1(cdata.Struct):
49    _pack_ = 1
50    _fields_ = [
51        ('header', TableHeader),
52        ('firmware_ctrl', ctypes.c_uint32),
53        ('dsdt', ctypes.c_uint32),
54        ('int_model', ctypes.c_uint8),
55        ('reserved0', ctypes.c_uint8),
56        ('sci_int', ctypes.c_uint16),
57        ('smi_cmd', ctypes.c_uint32),
58        ('acpi_enable', ctypes.c_uint8),
59        ('acpi_disable', ctypes.c_uint8),
60        ('s4bios_req', ctypes.c_uint8),
61        ('reserved1', ctypes.c_uint8),
62        ('pm1a_evt_blk', ctypes.c_uint32),
63        ('pm1b_evt_blk', ctypes.c_uint32),
64        ('pm1a_cnt_blk', ctypes.c_uint32),
65        ('pm1b_cnt_blk', ctypes.c_uint32),
66        ('pm2_cnt_blk', ctypes.c_uint32),
67        ('pm_tmr_blk', ctypes.c_uint32),
68        ('gpe0_blk', ctypes.c_uint32),
69        ('gpe1_blk', ctypes.c_uint32),
70        ('pm1_evt_len', ctypes.c_uint8),
71        ('pm1_cnt_len', ctypes.c_uint8),
72        ('pm2_cnt_len', ctypes.c_uint8),
73        ('pm_tmr_len', ctypes.c_uint8),
74        ('gpe0_blk_len', ctypes.c_uint8),
75        ('gpe1_blk_len', ctypes.c_uint8),
76        ('gpe1_base', ctypes.c_uint8),
77        ('reserved2', ctypes.c_uint8),
78        ('p_lvl2_lat', ctypes.c_uint16),
79        ('p_lvl3_lat', ctypes.c_uint16),
80        ('flush_size', ctypes.c_uint16),
81        ('flush_stride', ctypes.c_uint16),
82        ('duty_offset', ctypes.c_uint8),
83        ('duty_width', ctypes.c_uint8),
84        ('day_alrm', ctypes.c_uint8),
85        ('mon_alrm', ctypes.c_uint8),
86        ('century', ctypes.c_uint8),
87        ('reserved3', ctypes.c_uint8 * 3),
88        ('flags', facp_flags_v1),
89    ]
90
91class facp_flags_bits_v3(cdata.Struct):
92    _pack_ = 1
93    _fields_ = copy.copy(facp_flags_bits_v1._fields_) + [
94        ('reset_reg_sup', ctypes.c_uint32, 1),
95        ('sealed_case', ctypes.c_uint32, 1),
96        ('headless', ctypes.c_uint32, 1),
97        ('cpu_sw_slp', ctypes.c_uint32, 1),
98        ('pci_exp_wak', ctypes.c_uint32, 1),
99        ('use_platform_clock', ctypes.c_uint32, 1),
100        ('s4_rtc_sts_valid', ctypes.c_uint32, 1),
101        ('remote_power_on_capable', ctypes.c_uint32, 1),
102        ('force_apic_cluster_mode', ctypes.c_uint32, 1),
103        ('force_apic_physical_destination_mode', ctypes.c_uint32, 1),
104    ]
105
106class facp_flags_v3(cdata.Union):
107    _pack_ = 1
108    _anonymous_ = ("bits",)
109    _fields_ = [
110        ('data', ctypes.c_uint32),
111        ('bits', facp_flags_bits_v3),
112    ]
113
114class facp_iapc_arch_bits_v3(cdata.Struct):
115    _pack_ = 1
116    _fields_ =  [
117        ('legacy_devices', ctypes.c_uint16, 1),
118        ('8042', ctypes.c_uint16, 1),
119        ('vga_not_present', ctypes.c_uint16, 1),
120        ('msi_not_supported', ctypes.c_uint16, 1),
121    ]
122
123class facp_iapc_arch_v3(cdata.Union):
124    _pack_ = 1
125    _anonymous_ = ("bits",)
126    _fields_ = [
127        ('data', ctypes.c_uint16),
128        ('bits', facp_iapc_arch_bits_v3),
129    ]
130
131class FACP_v3(cdata.Struct):
132    _pack_ = 1
133    _fields_ = [
134        ('header', TableHeader),
135        ('firmware_ctrl', ctypes.c_uint32),
136        ('dsdt', ctypes.c_uint32),
137        ('reserved0', ctypes.c_uint8),
138        ('preferred_pm_profile', ctypes.c_uint8),
139        ('sci_int', ctypes.c_uint16),
140        ('smi_cmd', ctypes.c_uint32),
141        ('acpi_enable', ctypes.c_uint8),
142        ('acpi_disable', ctypes.c_uint8),
143        ('s4bios_req', ctypes.c_uint8),
144        ('pstate_cnt', ctypes.c_uint8),
145        ('pm1a_evt_blk', ctypes.c_uint32),
146        ('pm1b_evt_blk', ctypes.c_uint32),
147        ('pm1a_cnt_blk', ctypes.c_uint32),
148        ('pm1b_cnt_blk', ctypes.c_uint32),
149        ('pm2_cnt_blk', ctypes.c_uint32),
150        ('pm_tmr_blk', ctypes.c_uint32),
151        ('gpe0_blk', ctypes.c_uint32),
152        ('gpe1_blk', ctypes.c_uint32),
153        ('pm1_evt_len', ctypes.c_uint8),
154        ('pm1_cnt_len', ctypes.c_uint8),
155        ('pm2_cnt_len', ctypes.c_uint8),
156        ('pm_tmr_len', ctypes.c_uint8),
157        ('gpe0_blk_len', ctypes.c_uint8),
158        ('gpe1_blk_len', ctypes.c_uint8),
159        ('gpe1_base', ctypes.c_uint8),
160        ('cst_cnt', ctypes.c_uint8),
161        ('p_lvl2_lat', ctypes.c_uint16),
162        ('p_lvl3_lat', ctypes.c_uint16),
163        ('flush_size', ctypes.c_uint16),
164        ('flush_stride', ctypes.c_uint16),
165        ('duty_offset', ctypes.c_uint8),
166        ('duty_width', ctypes.c_uint8),
167        ('day_alrm', ctypes.c_uint8),
168        ('mon_alrm', ctypes.c_uint8),
169        ('century', ctypes.c_uint8),
170        ('iapc_boot_arch', facp_iapc_arch_v3),
171        ('reserved1', ctypes.c_uint8),
172        ('flags', facp_flags_v3),
173        ('reset_reg', GAS),
174        ('reset_value', ctypes.c_uint8),
175        ('reserved2', ctypes.c_uint8 * 3),
176        ('x_firmware_ctrl', ctypes.c_uint64),
177        ('x_dsdt', ctypes.c_uint64),
178        ('x_pm1a_evt_blk', GAS),
179        ('x_pm1b_evt_blk', GAS),
180        ('x_pm1a_cnt_blk', GAS),
181        ('x_pm1b_cnt_blk', GAS),
182        ('x_pm2_cnt_blk', GAS),
183        ('x_pm_tmr_blk', GAS),
184        ('x_gpe0_blk', GAS),
185        ('x_gpe1_blk', GAS),
186    ]
187
188    _formats = {
189        'preferred_pm_profile': unpack.format_table("{}", _preferred_pm_profile),
190    }
191
192class facp_iapc_arch_bits_v4(cdata.Struct):
193    _pack_ = 1
194    _fields_ = copy.copy(facp_iapc_arch_bits_v3._fields_) + [
195        ('pcie_aspm_controls', ctypes.c_uint16, 1),
196    ]
197
198class facp_iapc_arch_v4(cdata.Union):
199    _pack_ = 1
200    _anonymous_ = ("bits",)
201    _fields_ = [
202        ('data', ctypes.c_uint16),
203        ('bits', facp_iapc_arch_bits_v4),
204    ]
205
206class FACP_v4(cdata.Struct):
207    _pack_ = 1
208    _fields_ = [
209        ('header', TableHeader),
210        ('firmware_ctrl', ctypes.c_uint32),
211        ('dsdt', ctypes.c_uint32),
212        ('reserved0', ctypes.c_uint8),
213        ('preferred_pm_profile', ctypes.c_uint8),
214        ('sci_int', ctypes.c_uint16),
215        ('smi_cmd', ctypes.c_uint32),
216        ('acpi_enable', ctypes.c_uint8),
217        ('acpi_disable', ctypes.c_uint8),
218        ('s4bios_req', ctypes.c_uint8),
219        ('pstate_cnt', ctypes.c_uint8),
220        ('pm1a_evt_blk', ctypes.c_uint32),
221        ('pm1b_evt_blk', ctypes.c_uint32),
222        ('pm1a_cnt_blk', ctypes.c_uint32),
223        ('pm1b_cnt_blk', ctypes.c_uint32),
224        ('pm2_cnt_blk', ctypes.c_uint32),
225        ('pm_tmr_blk', ctypes.c_uint32),
226        ('gpe0_blk', ctypes.c_uint32),
227        ('gpe1_blk', ctypes.c_uint32),
228        ('pm1_evt_len', ctypes.c_uint8),
229        ('pm1_cnt_len', ctypes.c_uint8),
230        ('pm2_cnt_len', ctypes.c_uint8),
231        ('pm_tmr_len', ctypes.c_uint8),
232        ('gpe0_blk_len', ctypes.c_uint8),
233        ('gpe1_blk_len', ctypes.c_uint8),
234        ('gpe1_base', ctypes.c_uint8),
235        ('cst_cnt', ctypes.c_uint8),
236        ('p_lvl2_lat', ctypes.c_uint16),
237        ('p_lvl3_lat', ctypes.c_uint16),
238        ('flush_size', ctypes.c_uint16),
239        ('flush_stride', ctypes.c_uint16),
240        ('duty_offset', ctypes.c_uint8),
241        ('duty_width', ctypes.c_uint8),
242        ('day_alrm', ctypes.c_uint8),
243        ('mon_alrm', ctypes.c_uint8),
244        ('century', ctypes.c_uint8),
245        ('iapc_boot_arch', facp_iapc_arch_v4),
246        ('reserved1', ctypes.c_uint8),
247        ('flags', facp_flags_v3),
248        ('reset_reg', GAS),
249        ('reset_value', ctypes.c_uint8),
250        ('reserved2', ctypes.c_uint8 * 3),
251        ('x_firmware_ctrl', ctypes.c_uint64),
252        ('x_dsdt', ctypes.c_uint64),
253        ('x_pm1a_evt_blk', GAS),
254        ('x_pm1b_evt_blk', GAS),
255        ('x_pm1a_cnt_blk', GAS),
256        ('x_pm1b_cnt_blk', GAS),
257        ('x_pm2_cnt_blk', GAS),
258        ('x_pm_tmr_blk', GAS),
259        ('x_gpe0_blk', GAS),
260        ('x_gpe1_blk', GAS),
261    ]
262
263    _formats = {
264        'preferred_pm_profile': unpack.format_table("{}", _preferred_pm_profile),
265    }
266
267class facp_flags_bits_v5(cdata.Struct):
268    _pack_ = 1
269    _fields_ = copy.copy(facp_flags_bits_v3._fields_) + [
270        ('hw_reduced_acpi', ctypes.c_uint32, 1),
271        ('low_power_s0_idle_capable', ctypes.c_uint32, 1),
272    ]
273
274class facp_flags_v5(cdata.Union):
275    _pack_ = 1
276    _anonymous_ = ("bits",)
277    _fields_ = [
278        ('data', ctypes.c_uint32),
279        ('bits', facp_flags_bits_v5),
280    ]
281
282class facp_iapc_arch_bits_v5(cdata.Struct):
283    _pack_ = 1
284    _fields_ = copy.copy(facp_iapc_arch_bits_v4._fields_) + [
285        ('cmos_rtc_not_present', ctypes.c_uint16, 1),
286    ]
287
288class facp_iapc_arch_v5(cdata.Union):
289    _pack_ = 1
290    _anonymous_ = ("bits",)
291    _fields_ = [
292        ('data', ctypes.c_uint16),
293        ('bits', facp_iapc_arch_bits_v5),
294    ]
295
296class FACP_v5(cdata.Struct):
297    _pack_ = 1
298    _fields_ = [
299        ('header', TableHeader),
300        ('firmware_ctrl', ctypes.c_uint32),
301        ('dsdt', ctypes.c_uint32),
302        ('reserved0', ctypes.c_uint8),
303        ('preferred_pm_profile', ctypes.c_uint8),
304        ('sci_int', ctypes.c_uint16),
305        ('smi_cmd', ctypes.c_uint32),
306        ('acpi_enable', ctypes.c_uint8),
307        ('acpi_disable', ctypes.c_uint8),
308        ('s4bios_req', ctypes.c_uint8),
309        ('pstate_cnt', ctypes.c_uint8),
310        ('pm1a_evt_blk', ctypes.c_uint32),
311        ('pm1b_evt_blk', ctypes.c_uint32),
312        ('pm1a_cnt_blk', ctypes.c_uint32),
313        ('pm1b_cnt_blk', ctypes.c_uint32),
314        ('pm2_cnt_blk', ctypes.c_uint32),
315        ('pm_tmr_blk', ctypes.c_uint32),
316        ('gpe0_blk', ctypes.c_uint32),
317        ('gpe1_blk', ctypes.c_uint32),
318        ('pm1_evt_len', ctypes.c_uint8),
319        ('pm1_cnt_len', ctypes.c_uint8),
320        ('pm2_cnt_len', ctypes.c_uint8),
321        ('pm_tmr_len', ctypes.c_uint8),
322        ('gpe0_blk_len', ctypes.c_uint8),
323        ('gpe1_blk_len', ctypes.c_uint8),
324        ('gpe1_base', ctypes.c_uint8),
325        ('cst_cnt', ctypes.c_uint8),
326        ('p_lvl2_lat', ctypes.c_uint16),
327        ('p_lvl3_lat', ctypes.c_uint16),
328        ('flush_size', ctypes.c_uint16),
329        ('flush_stride', ctypes.c_uint16),
330        ('duty_offset', ctypes.c_uint8),
331        ('duty_width', ctypes.c_uint8),
332        ('day_alrm', ctypes.c_uint8),
333        ('mon_alrm', ctypes.c_uint8),
334        ('century', ctypes.c_uint8),
335        ('iapc_boot_arch', facp_iapc_arch_v5),
336        ('reserved1', ctypes.c_uint8),
337        ('flags', facp_flags_v5),
338        ('reset_reg', GAS),
339        ('reset_value', ctypes.c_uint8),
340        ('reserved2', ctypes.c_uint8 * 3),
341        ('x_firmware_ctrl', ctypes.c_uint64),
342        ('x_dsdt', ctypes.c_uint64),
343        ('x_pm1a_evt_blk', GAS),
344        ('x_pm1b_evt_blk', GAS),
345        ('x_pm1a_cnt_blk', GAS),
346        ('x_pm1b_cnt_blk', GAS),
347        ('x_pm2_cnt_blk', GAS),
348        ('x_pm_tmr_blk', GAS),
349        ('x_gpe0_blk', GAS),
350        ('x_gpe1_blk', GAS),
351        ('sleep_control_reg', GAS),
352        ('sleep_status_reg', GAS),
353    ]
354
355    _formats = {
356        'preferred_pm_profile': unpack.format_table("{}", _preferred_pm_profile),
357    }
358
359def FACP(val):
360    """Create class based on decode of an FACP table from filename."""
361    data = open(val, mode='rb').read()
362    buf = ctypes.create_string_buffer(data, len(data))
363    addr = ctypes.addressof(buf)
364    hdr = TableHeader.from_address(addr)
365    if hdr.revision < 3:
366        cls = FACP_v1
367    elif hdr.revision == 3:
368        cls = FACP_v3
369    elif hdr.revision == 4:
370        cls = FACP_v4
371    else:
372        cls = FACP_v5
373    return cls.from_buffer_copy(data)
374