1 | /* ----------------------------------------------------------------------- * |
---|
2 | * |
---|
3 | * Copyright 2009 Erwan Velu - All Rights Reserved |
---|
4 | * |
---|
5 | * Permission is hereby granted, free of charge, to any person |
---|
6 | * obtaining a copy of this software and associated documentation |
---|
7 | * files (the "Software"), to deal in the Software without |
---|
8 | * restriction, including without limitation the rights to use, |
---|
9 | * copy, modify, merge, publish, distribute, sublicense, and/or |
---|
10 | * sell copies of the Software, and to permit persons to whom |
---|
11 | * the Software is furnished to do so, subject to the following |
---|
12 | * conditions: |
---|
13 | * |
---|
14 | * The above copyright notice and this permission notice shall |
---|
15 | * be included in all copies or substantial portions of the Software. |
---|
16 | * |
---|
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
---|
19 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
---|
20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
---|
21 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
---|
22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
---|
23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
---|
24 | * OTHER DEALINGS IN THE SOFTWARE. |
---|
25 | * |
---|
26 | * ----------------------------------------------------------------------- |
---|
27 | */ |
---|
28 | |
---|
29 | #include "hdt-cli.h" |
---|
30 | #include "hdt-common.h" |
---|
31 | #include <stdio.h> |
---|
32 | #include <string.h> |
---|
33 | #include <stdlib.h> |
---|
34 | #include <errno.h> |
---|
35 | #include <acpi/acpi.h> |
---|
36 | |
---|
37 | /* Print ACPI's table header in a defined formating */ |
---|
38 | static void show_header(void *address, s_acpi_description_header * h) |
---|
39 | { |
---|
40 | more_printf("%-4s v%03x %-6s %-8s 0x%08x %-7s 0x%08x @ 0x%p\n", |
---|
41 | h->signature, h->revision, h->oem_id, h->oem_table_id, |
---|
42 | h->oem_revision, h->creator_id, h->creator_revision, address) |
---|
43 | } |
---|
44 | |
---|
45 | /* That's an helper to visualize columns*/ |
---|
46 | static void show_table_separator(void) |
---|
47 | { |
---|
48 | more_printf |
---|
49 | ("----|----|------|--------|----------|-------|-----------|--------------------\n"); |
---|
50 | } |
---|
51 | |
---|
52 | /* Display the main header before displaying the ACPI tables */ |
---|
53 | static void show_table_name(void) |
---|
54 | { |
---|
55 | more_printf |
---|
56 | ("ACPI rev oem table_id oem_rev creator creat_rev @ address \n"); |
---|
57 | show_table_separator(); |
---|
58 | } |
---|
59 | |
---|
60 | /* called by "show acpi" */ |
---|
61 | void main_show_acpi(int argc __unused, char **argv __unused, |
---|
62 | struct s_hardware *hardware) |
---|
63 | { |
---|
64 | reset_more_printf(); |
---|
65 | |
---|
66 | if (hardware->is_acpi_valid == false) { |
---|
67 | more_printf("No ACPI Tables detected\n"); |
---|
68 | return; |
---|
69 | } |
---|
70 | |
---|
71 | show_table_name(); |
---|
72 | |
---|
73 | /* RSDP tables aren't using the same headers as the other |
---|
74 | * So let's use a dedicated rendering */ |
---|
75 | if (hardware->acpi.rsdp.valid) { |
---|
76 | s_rsdp *r = &hardware->acpi.rsdp; |
---|
77 | more_printf |
---|
78 | ("RSDP v%03x %-6s @ %p\n", |
---|
79 | r->revision, r->oem_id, r->address); |
---|
80 | } |
---|
81 | |
---|
82 | if (hardware->acpi.rsdt.valid) |
---|
83 | show_header(hardware->acpi.rsdt.address, |
---|
84 | &hardware->acpi.rsdt.header); |
---|
85 | |
---|
86 | if (hardware->acpi.xsdt.valid) |
---|
87 | show_header(hardware->acpi.xsdt.address, |
---|
88 | &hardware->acpi.xsdt.header); |
---|
89 | |
---|
90 | if (hardware->acpi.fadt.valid) |
---|
91 | show_header(hardware->acpi.fadt.address, &hardware->acpi.fadt.header); |
---|
92 | |
---|
93 | if (hardware->acpi.dsdt.valid) |
---|
94 | show_header(hardware->acpi.dsdt.address, &hardware->acpi.dsdt.header); |
---|
95 | |
---|
96 | /* SSDT includes many optional tables, let's display them */ |
---|
97 | for (int i = 0; i < hardware->acpi.ssdt_count; i++) { |
---|
98 | if ((hardware->acpi.ssdt[i] != NULL) && (hardware->acpi.ssdt[i]->valid)) |
---|
99 | show_header(hardware->acpi.ssdt[i]->address, |
---|
100 | &hardware->acpi.ssdt[i]->header); |
---|
101 | } |
---|
102 | |
---|
103 | if (hardware->acpi.sbst.valid) |
---|
104 | show_header(hardware->acpi.sbst.address, &hardware->acpi.sbst.header); |
---|
105 | |
---|
106 | if (hardware->acpi.ecdt.valid) |
---|
107 | show_header(hardware->acpi.ecdt.address, &hardware->acpi.ecdt.header); |
---|
108 | |
---|
109 | if (hardware->acpi.hpet.valid) |
---|
110 | show_header(hardware->acpi.hpet.address, &hardware->acpi.hpet.header); |
---|
111 | |
---|
112 | if (hardware->acpi.tcpa.valid) |
---|
113 | show_header(hardware->acpi.tcpa.address, &hardware->acpi.tcpa.header); |
---|
114 | |
---|
115 | if (hardware->acpi.mcfg.valid) |
---|
116 | show_header(hardware->acpi.mcfg.address, &hardware->acpi.mcfg.header); |
---|
117 | |
---|
118 | if (hardware->acpi.slic.valid) |
---|
119 | show_header(hardware->acpi.slic.address, &hardware->acpi.slic.header); |
---|
120 | |
---|
121 | if (hardware->acpi.boot.valid) |
---|
122 | show_header(hardware->acpi.boot.address, &hardware->acpi.boot.header); |
---|
123 | |
---|
124 | /* FACS isn't having the same headers, let's use a dedicated rendering */ |
---|
125 | if (hardware->acpi.facs.valid) { |
---|
126 | s_facs *fa = &hardware->acpi.facs; |
---|
127 | more_printf |
---|
128 | ("FACS @ 0x%p\n", |
---|
129 | fa->address); |
---|
130 | } |
---|
131 | |
---|
132 | if (hardware->acpi.madt.valid) |
---|
133 | show_header(hardware->acpi.madt.address, &hardware->acpi.madt.header); |
---|
134 | |
---|
135 | more_printf("\nLocal APIC at 0x%08x\n", hardware->acpi.madt.local_apic_address); |
---|
136 | } |
---|
137 | |
---|
138 | /* Let's display the Processor Local APIC configuration */ |
---|
139 | static void show_local_apic(s_madt * madt) |
---|
140 | { |
---|
141 | if (madt->processor_local_apic_count == 0) { |
---|
142 | more_printf("No Processor Local APIC found\n"); |
---|
143 | return; |
---|
144 | } |
---|
145 | |
---|
146 | /* For all detected logical CPU */ |
---|
147 | for (int i = 0; i < madt->processor_local_apic_count; i++) { |
---|
148 | s_processor_local_apic *sla = &madt->processor_local_apic[i]; |
---|
149 | char buffer[8]; |
---|
150 | memset(buffer, 0, sizeof(buffer)); |
---|
151 | strcpy(buffer, "disable"); |
---|
152 | /* Let's check if the flags reports the cpu as enabled */ |
---|
153 | if ((sla->flags & PROCESSOR_LOCAL_APIC_ENABLE) == |
---|
154 | PROCESSOR_LOCAL_APIC_ENABLE) |
---|
155 | strcpy(buffer, "enable"); |
---|
156 | more_printf("CPU #%u, LAPIC (acpi_id[0x%02x] apic_id[0x%02x]) %s\n", |
---|
157 | sla->apic_id, sla->acpi_id, sla->apic_id, buffer); |
---|
158 | } |
---|
159 | } |
---|
160 | |
---|
161 | /* Display the local apic NMI configuration */ |
---|
162 | static void show_local_apic_nmi(s_madt * madt) |
---|
163 | { |
---|
164 | if (madt->local_apic_nmi_count == 0) { |
---|
165 | more_printf("No Local APIC NMI found\n"); |
---|
166 | return; |
---|
167 | } |
---|
168 | |
---|
169 | for (int i = 0; i < madt->local_apic_nmi_count; i++) { |
---|
170 | s_local_apic_nmi *slan = &madt->local_apic_nmi[i]; |
---|
171 | char buffer[20]; |
---|
172 | more_printf("LAPIC_NMI (acpi_id[0x%02x] %s lint(0x%02x))\n", |
---|
173 | slan->acpi_processor_id, flags_to_string(buffer, |
---|
174 | slan->flags), |
---|
175 | slan->local_apic_lint); |
---|
176 | } |
---|
177 | } |
---|
178 | |
---|
179 | /* Display the IO APIC configuration */ |
---|
180 | static void show_io_apic(s_madt * madt) |
---|
181 | { |
---|
182 | if (madt->io_apic_count == 0) { |
---|
183 | more_printf("No IO APIC found\n"); |
---|
184 | return; |
---|
185 | } |
---|
186 | |
---|
187 | /* For all IO APICS */ |
---|
188 | for (int i = 0; i < madt->io_apic_count; i++) { |
---|
189 | s_io_apic *sio = &madt->io_apic[i]; |
---|
190 | char buffer[15]; |
---|
191 | memset(buffer, 0, sizeof(buffer)); |
---|
192 | /* GSI base reports the GSI configuration |
---|
193 | * Let's interpret it as string */ |
---|
194 | switch (sio->global_system_interrupt_base) { |
---|
195 | case 0: |
---|
196 | strcpy(buffer, "GSI 0-23"); |
---|
197 | break; |
---|
198 | case 24: |
---|
199 | strcpy(buffer, "GSI 24-39"); |
---|
200 | break; |
---|
201 | case 40: |
---|
202 | strcpy(buffer, "GSI 40-55"); |
---|
203 | break; |
---|
204 | default: |
---|
205 | strcpy(buffer, "GSI Unknown"); |
---|
206 | break; |
---|
207 | } |
---|
208 | |
---|
209 | more_printf("IO_APIC[%d] : apic_id[0x%02x] address[0x%08x] %s\n", |
---|
210 | i, sio->io_apic_id, sio->io_apic_address, buffer); |
---|
211 | } |
---|
212 | } |
---|
213 | |
---|
214 | /* Display the interrupt source override configuration */ |
---|
215 | static void show_interrupt_source_override(s_madt * madt) |
---|
216 | { |
---|
217 | if (madt->interrupt_source_override_count == 0) { |
---|
218 | more_printf("No interrupt source override found\n"); |
---|
219 | return; |
---|
220 | } |
---|
221 | |
---|
222 | /* Let's process each interrupt source override */ |
---|
223 | for (int i = 0; i < madt->interrupt_source_override_count; i++) { |
---|
224 | s_interrupt_source_override *siso = &madt->interrupt_source_override[i]; |
---|
225 | char buffer[20]; |
---|
226 | char bus_type[10]; |
---|
227 | memset(bus_type, 0, sizeof(bus_type)); |
---|
228 | /* Spec report bus type 0 as ISA */ |
---|
229 | if (siso->bus == 0) |
---|
230 | strcpy(bus_type, "ISA"); |
---|
231 | else |
---|
232 | strcpy(bus_type, "unknown"); |
---|
233 | |
---|
234 | more_printf("INT_SRC_OVR (bus %s (%d) bus_irq %d global_irq %d %s)\n", |
---|
235 | bus_type, siso->bus, siso->source, |
---|
236 | siso->global_system_interrupt, flags_to_string(buffer, |
---|
237 | siso-> |
---|
238 | flags)); |
---|
239 | } |
---|
240 | } |
---|
241 | |
---|
242 | /* Display the apic configuration |
---|
243 | * This is called by acpi> show apic */ |
---|
244 | static void show_acpi_apic(int argc __unused, char **argv __unused, |
---|
245 | struct s_hardware *hardware) |
---|
246 | { |
---|
247 | if (hardware->is_acpi_valid == false) { |
---|
248 | more_printf("No ACPI Tables detected\n"); |
---|
249 | return; |
---|
250 | } |
---|
251 | |
---|
252 | s_madt *madt = &hardware->acpi.madt; |
---|
253 | |
---|
254 | if (madt->valid == false) { |
---|
255 | more_printf("No APIC (MADT) table found\n"); |
---|
256 | return; |
---|
257 | } |
---|
258 | |
---|
259 | more_printf("Local APIC at 0x%08x\n", madt->local_apic_address); |
---|
260 | show_local_apic(madt); |
---|
261 | show_local_apic_nmi(madt); |
---|
262 | show_io_apic(madt); |
---|
263 | show_interrupt_source_override(madt); |
---|
264 | } |
---|
265 | |
---|
266 | struct cli_callback_descr list_acpi_show_modules[] = { |
---|
267 | { |
---|
268 | .name = "apic", |
---|
269 | .exec = show_acpi_apic, |
---|
270 | .nomodule = false, |
---|
271 | }, |
---|
272 | { |
---|
273 | .name = NULL, |
---|
274 | .exec = NULL, |
---|
275 | .nomodule = false, |
---|
276 | }, |
---|
277 | }; |
---|
278 | |
---|
279 | struct cli_module_descr acpi_show_modules = { |
---|
280 | .modules = list_acpi_show_modules, |
---|
281 | .default_callback = main_show_acpi, |
---|
282 | }; |
---|
283 | |
---|
284 | struct cli_mode_descr acpi_mode = { |
---|
285 | .mode = ACPI_MODE, |
---|
286 | .name = CLI_ACPI, |
---|
287 | .default_modules = NULL, |
---|
288 | .show_modules = &acpi_show_modules, |
---|
289 | .set_modules = NULL, |
---|
290 | }; |
---|