1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * This software may be distributed and modified according to the terms of 5 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 6 * See "LICENSE_GPLv2.txt" for details. 7 * 8 * @TAG(GD_GPL) 9 */ 10 11#include <config.h> 12#include <util.h> 13#include <assert.h> 14#include <machine/io.h> 15#include <linker.h> 16#include <plat/machine.h> 17#include <plat/machine/acpi.h> 18#include <plat/machine/devices.h> 19 20enum acpi_type { 21 ACPI_RSDP, 22 ACPI_RSDT 23}; 24 25/* DMA Remapping Reporting Table */ 26typedef struct acpi_dmar { 27 acpi_header_t header; 28 uint8_t host_addr_width; 29 uint8_t flags; 30 uint8_t reserved[10]; 31} acpi_dmar_t; 32compile_assert(acpi_dmar_packed, 33 sizeof(acpi_dmar_t) == sizeof(acpi_header_t) + 12) 34 35/* DMA Remapping Structure Header */ 36typedef struct acpi_dmar_header { 37 uint16_t type; 38 uint16_t length; 39} acpi_dmar_header_t; 40compile_assert(acpi_dmar_header_packed, sizeof(acpi_dmar_header_t) == 4) 41 42/* DMA Remapping Structure Types */ 43enum acpi_table_dmar_struct_type { 44 DMAR_DRHD = 0, 45 DMAR_RMRR = 1, 46 DMAR_ATSR = 2, 47}; 48 49/* DMA Remapping Hardware unit Definition */ 50typedef struct acpi_dmar_drhd { 51 acpi_dmar_header_t header; 52 uint8_t flags; 53 uint8_t reserved; 54 uint16_t segment; 55 uint32_t reg_base[2]; 56} acpi_dmar_drhd_t; 57compile_assert(acpi_dmar_drhd_packed, 58 sizeof(acpi_dmar_drhd_t) == sizeof(acpi_dmar_header_t) + 12) 59 60/* Reserved Memory Region Reporting structure Definition */ 61typedef struct acpi_dmar_devscope { 62 uint8_t type; 63 uint8_t length; 64 uint16_t reserved; 65 uint8_t enum_id; 66 uint8_t start_bus; 67 struct { 68 uint8_t dev; 69 uint8_t fun; 70 } path_0; 71} acpi_dmar_devscope_t; 72compile_assert(acpi_dmar_devscope_packed, sizeof(acpi_dmar_devscope_t) == 8) 73 74/* Reserved Memory Region Reporting structure Definition */ 75typedef struct acpi_dmar_rmrr { 76 acpi_dmar_header_t header; 77 uint16_t reserved; 78 uint16_t segment; 79 uint32_t reg_base[2]; 80 uint32_t reg_limit[2]; 81 acpi_dmar_devscope_t devscope_0; 82} acpi_dmar_rmrr_t; 83compile_assert(acpi_dmar_rmrr_packed, sizeof(acpi_dmar_rmrr_t) == 84 sizeof(acpi_dmar_header_t) + 20 + sizeof(acpi_dmar_devscope_t)) 85 86/* Fixed ACPI Description Table (FADT), partial as we only need flags */ 87typedef struct acpi_fadt { 88 acpi_header_t header; 89 uint8_t reserved[76]; 90 uint32_t flags; 91} acpi_fadt_t; 92compile_assert(acpi_fadt_packed, 93 sizeof(acpi_fadt_t) == sizeof(acpi_header_t) + 80) 94 95/* Multiple APIC Description Table (MADT) */ 96typedef struct acpi_madt { 97 acpi_header_t header; 98 uint32_t apic_addr; 99 uint32_t flags; 100} acpi_madt_t; 101compile_assert(acpi_madt_packed, 102 sizeof(acpi_madt_t) == sizeof(acpi_header_t) + 8) 103 104typedef struct acpi_madt_header { 105 uint8_t type; 106 uint8_t length; 107} acpi_madt_header_t; 108compile_assert(acpi_madt_header_packed, sizeof(acpi_madt_header_t) == 2) 109 110enum acpi_table_madt_struct_type { 111 MADT_APIC = 0, 112 MADT_IOAPIC = 1, 113 MADT_ISO = 2, 114 MADT_x2APIC = 9 115}; 116 117typedef struct acpi_madt_apic { 118 acpi_madt_header_t header; 119 uint8_t cpu_id; 120 uint8_t apic_id; 121 uint32_t flags; 122} acpi_madt_apic_t; 123compile_assert(acpi_madt_apic_packed, 124 sizeof(acpi_madt_apic_t) == sizeof(acpi_madt_header_t) + 6) 125 126typedef struct acpi_madt_x2apic { 127 acpi_madt_header_t header; 128 uint16_t reserved; 129 uint32_t x2apic_id; 130 uint32_t flags; 131 uint32_t acpi_processor_uid; 132} acpi_madt_x2apic_t; 133compile_assert(acpi_madt_x2apic_packed, 134 sizeof(acpi_madt_x2apic_t) == sizeof(acpi_madt_header_t) + 14) 135 136typedef struct acpi_madt_ioapic { 137 acpi_madt_header_t header; 138 uint8_t ioapic_id; 139 uint8_t reserved[1]; 140 uint32_t ioapic_addr; 141 uint32_t gsib; 142} acpi_madt_ioapic_t; 143compile_assert(acpi_madt_ioapic_packed, 144 sizeof(acpi_madt_ioapic_t) == sizeof(acpi_madt_header_t) + 10) 145 146typedef struct acpi_madt_iso { 147 acpi_madt_header_t header; 148 uint8_t bus; /* always 0 (ISA) */ 149 uint8_t source; 150 uint32_t gsi; 151 uint16_t flags; 152} acpi_madt_iso_t; 153/* We can't assert on the sizeof acpi_madt_iso because it contains trailing 154 * padding. 155 */ 156unverified_compile_assert(acpi_madt_iso_packed, 157 OFFSETOF(acpi_madt_iso_t, flags) == sizeof(acpi_madt_header_t) + 6) 158 159/* workaround because string literals are not supported by C parser */ 160const char acpi_str_rsd[] = {'R', 'S', 'D', ' ', 'P', 'T', 'R', ' ', 0}; 161const char acpi_str_fadt[] = {'F', 'A', 'C', 'P', 0}; 162const char acpi_str_apic[] = {'A', 'P', 'I', 'C', 0}; 163const char acpi_str_dmar[] = {'D', 'M', 'A', 'R', 0}; 164 165BOOT_CODE static uint8_t 166acpi_calc_checksum(char* start, uint32_t length) 167{ 168 uint8_t checksum = 0; 169 170 while (length > 0) { 171 checksum += *start; 172 start++; 173 length--; 174 } 175 return checksum; 176} 177 178BOOT_CODE static acpi_rsdp_t* 179acpi_get_rsdp(void) 180{ 181 char* addr; 182 183 for (addr = (char*)BIOS_PADDR_START; addr < (char*)BIOS_PADDR_END; addr += 16) { 184 if (strncmp(addr, acpi_str_rsd, 8) == 0) { 185 if (acpi_calc_checksum(addr, ACPI_V1_SIZE) == 0) { 186 return (acpi_rsdp_t*)addr; 187 } 188 } 189 } 190 return NULL; 191} 192 193BOOT_CODE static void* 194acpi_table_init(void* entry, enum acpi_type table_type) 195{ 196 void* acpi_table; 197 unsigned int pages_for_table; 198 unsigned int pages_for_header = 1; 199 200 /* if we need to map another page to read header */ 201 unsigned long offset_in_page = (unsigned long)entry & MASK(LARGE_PAGE_BITS); 202 if (MASK(LARGE_PAGE_BITS) - offset_in_page < sizeof(acpi_rsdp_t)) { 203 pages_for_header++; 204 } 205 206 /* map in table's header */ 207 acpi_table = map_temp_boot_page(entry, pages_for_header); 208 209 switch (table_type) { 210 case ACPI_RSDP: { 211 acpi_rsdp_t *rsdp_entry = (acpi_rsdp_t*)entry; 212 pages_for_table = (rsdp_entry->length + offset_in_page) / MASK(LARGE_PAGE_BITS) + 1; 213 break; 214 } 215 case ACPI_RSDT: { // RSDT, MADT, DMAR etc. 216 acpi_rsdt_t *rsdt_entry = (acpi_rsdt_t*)entry; 217 pages_for_table = (rsdt_entry->header.length + offset_in_page) / MASK(LARGE_PAGE_BITS) + 1; 218 break; 219 } 220 default: 221 printf("Error: Mapping unknown ACPI table type\n"); 222 assert(false); 223 return NULL; 224 } 225 226 /* map in full table */ 227 acpi_table = map_temp_boot_page(entry, pages_for_table); 228 229 return acpi_table; 230} 231 232BOOT_CODE bool_t 233acpi_init(acpi_rsdp_t *rsdp_data) 234{ 235 acpi_rsdp_t* acpi_rsdp = acpi_get_rsdp(); 236 237 if (acpi_rsdp == NULL) { 238 printf("BIOS: No ACPI support detected\n"); 239 return false; 240 } 241 printf("ACPI: RSDP paddr=%p\n", acpi_rsdp); 242 acpi_rsdp = acpi_table_init(acpi_rsdp, ACPI_RSDP); 243 printf("ACPI: RSDP vaddr=%p\n", acpi_rsdp); 244 245 /* create a copy of the rsdp data */ 246 *rsdp_data = *acpi_rsdp; 247 248 /* perform final validation */ 249 return acpi_validate_rsdp(rsdp_data); 250} 251 252BOOT_CODE bool_t 253acpi_validate_rsdp(acpi_rsdp_t *acpi_rsdp) 254{ 255 acpi_rsdt_t* acpi_rsdt; 256 acpi_rsdt_t* acpi_rsdt_mapped; 257 258 if (acpi_calc_checksum((char*)acpi_rsdp, ACPI_V1_SIZE) != 0) { 259 printf("BIOS: ACPIv1 information corrupt\n"); 260 return false; 261 } 262 263 if (acpi_rsdp->revision > 0 && acpi_calc_checksum((char*)acpi_rsdp, sizeof(*acpi_rsdp)) != 0) { 264 printf("BIOS: ACPIv2 information corrupt\n"); 265 return false; 266 } 267 268 /* verify the rsdt, even though we do not actually make use of the mapping right now */ 269 acpi_rsdt = (acpi_rsdt_t*)(word_t)acpi_rsdp->rsdt_address; 270 printf("ACPI: RSDT paddr=%p\n", acpi_rsdt); 271 acpi_rsdt_mapped = (acpi_rsdt_t*)acpi_table_init(acpi_rsdt, ACPI_RSDT); 272 printf("ACPI: RSDT vaddr=%p\n", acpi_rsdt_mapped); 273 274 assert(acpi_rsdt_mapped->header.length > 0); 275 if (acpi_calc_checksum((char*)acpi_rsdt_mapped, acpi_rsdt_mapped->header.length) != 0) { 276 printf("ACPI: RSDT checksum failure\n"); 277 return false; 278 } 279 280 return true; 281} 282 283BOOT_CODE uint32_t 284acpi_madt_scan( 285 acpi_rsdp_t* acpi_rsdp, 286 cpu_id_t* cpu_list, 287 uint32_t* num_ioapic, 288 paddr_t* ioapic_paddrs 289) 290{ 291 unsigned int entries; 292 uint32_t num_cpu; 293 uint32_t count; 294 acpi_madt_t* acpi_madt; 295 acpi_madt_header_t* acpi_madt_header; 296 297 acpi_rsdt_t* acpi_rsdt_mapped; 298 acpi_madt_t* acpi_madt_mapped; 299 acpi_rsdt_mapped = (acpi_rsdt_t*)acpi_table_init((acpi_rsdt_t*)(word_t)acpi_rsdp->rsdt_address, ACPI_RSDT); 300 301 num_cpu = 0; 302 *num_ioapic = 0; 303 304 assert(acpi_rsdt_mapped->header.length >= sizeof(acpi_header_t)); 305 /* Divide by uint32_t explicitly as this is the size as mandated by the ACPI standard */ 306 entries = (acpi_rsdt_mapped->header.length - sizeof(acpi_header_t)) / sizeof(uint32_t); 307 for (count = 0; count < entries; count++) { 308 acpi_madt = (acpi_madt_t*)(word_t)acpi_rsdt_mapped->entry[count]; 309 acpi_madt_mapped = (acpi_madt_t*)acpi_table_init(acpi_madt, ACPI_RSDT); 310 311 if (strncmp(acpi_str_apic, acpi_madt_mapped->header.signature, 4) == 0) { 312 printf("ACPI: MADT paddr=%p\n", acpi_madt); 313 printf("ACPI: MADT vaddr=%p\n", acpi_madt_mapped); 314 printf("ACPI: MADT apic_addr=0x%x\n", acpi_madt_mapped->apic_addr); 315 printf("ACPI: MADT flags=0x%x\n", acpi_madt_mapped->flags); 316 317 acpi_madt_header = (acpi_madt_header_t*)(acpi_madt_mapped + 1); 318 319 while ((char*)acpi_madt_header < (char*)acpi_madt_mapped + acpi_madt_mapped->header.length) { 320 switch (acpi_madt_header->type) { 321 /* ACPI specifies the following rules when listing APIC IDs: 322 * - Boot processor is listed first 323 * - For multi-threaded processors, BIOS should list the first logical 324 * processor of each of the individual multi-threaded processors in MADT 325 * before listing any of the second logical processors. 326 * - APIC IDs < 0xFF should be listed in APIC subtable, APIC IDs >= 0xFF 327 * should be listed in X2APIC subtable */ 328 case MADT_APIC: { 329 /* what Intel calls apic_id is what is called cpu_id in seL4! */ 330 uint8_t cpu_id = ((acpi_madt_apic_t*)acpi_madt_header)->apic_id; 331 uint32_t flags = ((acpi_madt_apic_t*)acpi_madt_header)->flags; 332 if (flags == 1) { 333 printf("ACPI: MADT_APIC apic_id=0x%x\n", cpu_id); 334 if (num_cpu == CONFIG_MAX_NUM_NODES) { 335 printf("ACPI: Not recording this APIC, only support %d\n", CONFIG_MAX_NUM_NODES); 336 } else { 337 cpu_list[num_cpu] = cpu_id; 338 num_cpu++; 339 } 340 } 341 break; 342 } 343 case MADT_x2APIC: { 344 uint32_t cpu_id = ((acpi_madt_x2apic_t*)acpi_madt_header)->x2apic_id; 345 uint32_t flags = ((acpi_madt_x2apic_t*)acpi_madt_header)->flags; 346 if (flags == 1) { 347 printf("ACPI: MADT_x2APIC apic_id=0x%x\n", cpu_id); 348 if (num_cpu == CONFIG_MAX_NUM_NODES) { 349 printf("ACPI: Not recording this APIC, only support %d\n", CONFIG_MAX_NUM_NODES); 350 } else { 351 cpu_list[num_cpu] = cpu_id; 352 num_cpu++; 353 } 354 } 355 break; 356 } 357 case MADT_IOAPIC: 358 printf( 359 "ACPI: MADT_IOAPIC ioapic_id=%d ioapic_addr=0x%x gsib=%d\n", 360 ((acpi_madt_ioapic_t*)acpi_madt_header)->ioapic_id, 361 ((acpi_madt_ioapic_t*)acpi_madt_header)->ioapic_addr, 362 ((acpi_madt_ioapic_t*)acpi_madt_header)->gsib 363 ); 364 if (*num_ioapic == CONFIG_MAX_NUM_IOAPIC) { 365 printf("ACPI: Not recording this IOAPIC, only support %d\n", CONFIG_MAX_NUM_IOAPIC); 366 } else { 367 ioapic_paddrs[*num_ioapic] = ((acpi_madt_ioapic_t*)acpi_madt_header)->ioapic_addr; 368 (*num_ioapic)++; 369 } 370 break; 371 case MADT_ISO: 372 printf("ACPI: MADT_ISO bus=%d source=%d gsi=%d flags=0x%x\n", 373 ((acpi_madt_iso_t*)acpi_madt_header)->bus, 374 ((acpi_madt_iso_t*)acpi_madt_header)->source, 375 ((acpi_madt_iso_t*)acpi_madt_header)->gsi, 376 ((acpi_madt_iso_t*)acpi_madt_header)->flags); 377 break; 378 default: 379 break; 380 } 381 acpi_madt_header = (acpi_madt_header_t*)((char*)acpi_madt_header + acpi_madt_header->length); 382 } 383 } 384 } 385 386 printf("ACPI: %d CPU(s) detected\n", num_cpu); 387 388 return num_cpu; 389} 390 391BOOT_CODE bool_t 392acpi_fadt_scan( 393 acpi_rsdp_t* acpi_rsdp 394) 395{ 396 unsigned int entries; 397 uint32_t count; 398 acpi_fadt_t* acpi_fadt; 399 400 acpi_rsdt_t* acpi_rsdt_mapped; 401 acpi_fadt_t* acpi_fadt_mapped; 402 acpi_rsdt_mapped = (acpi_rsdt_t*)acpi_table_init((acpi_rsdt_t*)(word_t)acpi_rsdp->rsdt_address, ACPI_RSDT); 403 404 assert(acpi_rsdt_mapped->header.length >= sizeof(acpi_header_t)); 405 /* Divide by uint32_t explicitly as this is the size as mandated by the ACPI standard */ 406 entries = (acpi_rsdt_mapped->header.length - sizeof(acpi_header_t)) / sizeof(uint32_t); 407 for (count = 0; count < entries; count++) { 408 acpi_fadt = (acpi_fadt_t*)(word_t)acpi_rsdt_mapped->entry[count]; 409 acpi_fadt_mapped = (acpi_fadt_t*)acpi_table_init(acpi_fadt, ACPI_RSDT); 410 411 if (strncmp(acpi_str_fadt, acpi_fadt_mapped->header.signature, 4) == 0) { 412 printf("ACPI: FADT paddr=%p\n", acpi_fadt); 413 printf("ACPI: FADT vaddr=%p\n", acpi_fadt_mapped); 414 printf("ACPI: FADT flags=0x%x\n", acpi_fadt_mapped->flags); 415 416 if (config_set(CONFIG_USE_LOGICAL_IDS) && 417 acpi_fadt_mapped->flags & BIT(19)) { 418 printf("system requires apic physical mode\n"); 419 return false; 420 } 421 } 422 } 423 424 return true; 425} 426 427BOOT_CODE void 428acpi_dmar_scan( 429 acpi_rsdp_t* acpi_rsdp, 430 paddr_t* drhu_list, 431 uint32_t* num_drhu, 432 uint32_t max_drhu_list_len, 433 acpi_rmrr_list_t *rmrr_list 434) 435{ 436 word_t i; 437 unsigned int entries; 438 uint32_t count; 439 uint32_t reg_basel, reg_baseh; 440 int rmrr_count; 441 dev_id_t dev_id; 442 443 acpi_dmar_t* acpi_dmar; 444 acpi_dmar_header_t* acpi_dmar_header; 445 acpi_dmar_rmrr_t* acpi_dmar_rmrr; 446 acpi_dmar_devscope_t* acpi_dmar_devscope; 447 448 acpi_rsdt_t* acpi_rsdt_mapped; 449 acpi_dmar_t* acpi_dmar_mapped; 450 451 acpi_rsdt_mapped = (acpi_rsdt_t*)acpi_table_init((acpi_rsdt_t*)(word_t)acpi_rsdp->rsdt_address, ACPI_RSDT); 452 453 *num_drhu = 0; 454 rmrr_count = 0; 455 456 assert(acpi_rsdt_mapped->header.length >= sizeof(acpi_header_t)); 457 entries = (acpi_rsdt_mapped->header.length - sizeof(acpi_header_t)) / sizeof(uint32_t); 458 for (count = 0; count < entries; count++) { 459 acpi_dmar = (acpi_dmar_t*)(word_t)acpi_rsdt_mapped->entry[count]; 460 acpi_dmar_mapped = (acpi_dmar_t*)acpi_table_init(acpi_dmar, ACPI_RSDT); 461 462 if (strncmp(acpi_str_dmar, acpi_dmar_mapped->header.signature, 4) == 0) { 463 printf("ACPI: DMAR paddr=%p\n", acpi_dmar); 464 printf("ACPI: DMAR vaddr=%p\n", acpi_dmar_mapped); 465 printf("ACPI: IOMMU host address width: %d\n", acpi_dmar_mapped->host_addr_width + 1); 466 acpi_dmar_header = (acpi_dmar_header_t*)(acpi_dmar_mapped + 1); 467 468 while ((char*)acpi_dmar_header < (char*)acpi_dmar_mapped + acpi_dmar_mapped->header.length) { 469 switch (acpi_dmar_header->type) { 470 471 case DMAR_DRHD: 472 if (*num_drhu == max_drhu_list_len) { 473 printf("ACPI: too many IOMMUs, disabling IOMMU support\n"); 474 /* try to increase MAX_NUM_DRHU in config.h */ 475 *num_drhu = 0; /* report zero IOMMUs */ 476 return; 477 } 478 reg_basel = ((acpi_dmar_drhd_t*)acpi_dmar_header)->reg_base[0]; 479 reg_baseh = ((acpi_dmar_drhd_t*)acpi_dmar_header)->reg_base[1]; 480 /* check if value fits into uint32_t */ 481 if (reg_baseh != 0) { 482 printf("ACPI: DMAR_DRHD reg_base exceeds 32 bit, disabling IOMMU support\n"); 483 /* try to make BIOS map it below 4G */ 484 *num_drhu = 0; /* report zero IOMMUs */ 485 return; 486 } 487 drhu_list[*num_drhu] = (paddr_t)reg_basel; 488 (*num_drhu)++; 489 break; 490 491 case DMAR_RMRR: 492 /* loop through all device scopes of this RMRR */ 493 acpi_dmar_rmrr = (acpi_dmar_rmrr_t*)acpi_dmar_header; 494 if (acpi_dmar_rmrr->reg_base[1] != 0 || 495 acpi_dmar_rmrr->reg_limit[1] != 0) { 496 printf("ACPI: RMRR device above 4GiB, disabling IOMMU support\n"); 497 *num_drhu = 0; 498 return ; 499 } 500 501 for (i = 0; i <= (acpi_dmar_header->length - sizeof(acpi_dmar_rmrr_t)) / sizeof(acpi_dmar_devscope_t); i++) { 502 acpi_dmar_devscope = &acpi_dmar_rmrr->devscope_0 + i; 503 504 if (acpi_dmar_devscope->type != 1) { 505 /* FIXME - bugzilla bug 170 */ 506 printf("ACPI: RMRR device scope: non-PCI-Endpoint-Devices not supported yet, disabling IOMMU support\n"); 507 *num_drhu = 0; /* report zero IOMMUs */ 508 return; 509 } 510 511 if (acpi_dmar_devscope->length > sizeof(acpi_dmar_devscope_t)) { 512 /* FIXME - bugzilla bug 170 */ 513 printf("ACPI: RMRR device scope: devices behind bridges not supported yet, disabling IOMMU support\n"); 514 *num_drhu = 0; /* report zero IOMMUs */ 515 return; 516 } 517 518 dev_id = 519 get_dev_id( 520 acpi_dmar_devscope->start_bus, 521 acpi_dmar_devscope->path_0.dev, 522 acpi_dmar_devscope->path_0.fun 523 ); 524 525 if (rmrr_count == CONFIG_MAX_RMRR_ENTRIES) { 526 printf("ACPI: Too many RMRR entries, disabling IOMMU support\n"); 527 *num_drhu = 0; 528 return; 529 } 530 printf("\tACPI: registering RMRR entry for region for device: bus=0x%x dev=0x%x fun=0x%x\n", 531 acpi_dmar_devscope->start_bus, 532 acpi_dmar_devscope->path_0.dev, 533 acpi_dmar_devscope->path_0.fun 534 ); 535 536 rmrr_list->entries[rmrr_count].device = dev_id; 537 rmrr_list->entries[rmrr_count].base = acpi_dmar_rmrr->reg_base[0]; 538 rmrr_list->entries[rmrr_count].limit = acpi_dmar_rmrr->reg_limit[0]; 539 rmrr_count++; 540 } 541 break; 542 543 case DMAR_ATSR: 544 /* not implemented yet */ 545 break; 546 547 default: 548 printf("ACPI: Unknown DMA remapping structure type: %x\n", acpi_dmar_header->type); 549 } 550 acpi_dmar_header = (acpi_dmar_header_t*)((char*)acpi_dmar_header + acpi_dmar_header->length); 551 } 552 } 553 } 554 rmrr_list->num = rmrr_count; 555 printf("ACPI: %d IOMMUs detected\n", *num_drhu); 556} 557