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 }; 291