void SIG() { SIG00(); SIG01(); SIG30(); SIG31(); SIG32(); SIG33(); SIG34(); }
static void *build_ivrs(struct IVRS *ivrs) { memset(ivrs, 0, sizeof(*ivrs)); ivrs->hdr.sig = SIG32('I', 'V', 'R', 'S'); ivrs->hdr.length = sizeof(*ivrs); ivrs->hdr.rev = 1; memcpy(ivrs->hdr.oem_id, "F0F ", 6); memcpy(ivrs->hdr.oem_tid, "PS4KEXEC", 8); ivrs->hdr.oem_rev = 0x20161225; memcpy(ivrs->hdr.creator_id, "KEXC", 4); ivrs->hdr.creator_rev = 0x20161225; ivrs->IVinfo = 0x00203040; struct ivhd_header *hdr = &ivrs->hd_hdr; hdr->type = 0x10; hdr->flags = /*coherent | */(1 << 5) | IVHD_FLAG_ISOC_EN_MASK; hdr->length = sizeof(ivrs->hd_hdr) + sizeof(ivrs->hd_entries); hdr->devid = PCI_DEVFN(0, 2); hdr->cap_ptr = 0x40; // from config space + 0x34 hdr->mmio_phys = 0xfc000000; hdr->pci_seg = 0; hdr->info = 0; // msi msg num? (the pci cap should be written by software) // HATS = 0b10, PNBanks = 2, PNCounters = 4, IASup = 1 hdr->efr_attr = (2 << 30) | (2 << 17) | (4 << 13) | (1 << 5); struct ivhd_entry4 *entries = &ivrs->hd_entries[0]; // on fbsd, all aeolia devfns have active entries except memories (func 6) // not sure if this is just because it wasn't in use when i dumped it? // all entries are r/w // IntCtl = 0b01 and IV = 1 are set for all entries (irqs are forwarded) // apcie has SysMgt = 0b11 (others are 0b00). (device-initiated dmas are translated) // Modes: // 4 level: // apcie // 3 level: // all others // the way to encode this info into the IVHD entries is fairly arbitrary... entries[0].type = IVHD_DEV_SELECT; entries[0].devid = PCI_DEVFN(20, 0); entries[0].flags = ACPI_DEVFLAG_SYSMGT1 | ACPI_DEVFLAG_SYSMGT2; entries[1].type = IVHD_DEV_SELECT_RANGE_START; entries[1].devid = PCI_DEVFN(20, 1); entries[1].flags = 0; entries[2].type = IVHD_DEV_RANGE_END; entries[2].devid = PCI_DEVFN(20, 7); entries[2].flags = 0; table_checksum(ivrs); return ivrs + 1; }
void fix_acpi_tables(void *map_base, u64 phys_base) { void *buf_base = map_base + 0x8000; void *p = buf_base; memset(buf_base, 0, 0x8000); printf("Fixing ACPI tables at 0x%llx (%p)\n", phys_base, map_base); struct RSDP *rsdp = COPYP(struct RSDP, phys_base); printf("RSDT at 0x%x\n", rsdp->rsdt_addr); printf("XSDT at 0x%llx\n", rsdp->xsdt_addr); struct RSDT *rsdt_src = P2M(rsdp->rsdt_addr); struct RSDT *rsdt = COPYTP(rsdp->rsdt_addr); rsdp->rsdt_addr = B2P(rsdt); PADB(0x30); // this gives us space for new tables struct XSDT *xsdt = COPYTP(rsdp->xsdt_addr); rsdp->xsdt_addr = B2P(xsdt); PADB(0x60); struct FADT *fadt = NULL; int cnt = (rsdt_src->hdr.length - sizeof(*rsdt)) / 4; int i; for (i = 0; i < cnt; i++) { struct SDTH *hdr = P2M(rsdt_src->table_addr[i]); printf("%c%c%c%c at 0x%x\n", PSIG32(hdr->sig), rsdt_src->table_addr[i]); switch (hdr->sig) { case SIG32('F', 'A', 'C', 'P'): { fadt = (void*)hdr; printf("FACS at 0x%x\n", fadt->facs); printf("DSDT at 0x%x\n", fadt->dsdt); // Sony puts the FACS before the FADT, unaligned, which is // noncompliant, but let's keep it there u8 *facs = COPYB(64, P2M(fadt->facs)); fadt = (void*)(hdr = COPYT(hdr)); fadt->facs = B2P(facs); PADB(0x38); break; } case SIG32('S', 'S', 'D', 'T'): { // Put the DSDT before the SSDT if (fadt) { PADB(0xf0); u8 *dsdt = COPYTP(fadt->dsdt); fadt->dsdt = B2P(dsdt); PADB(0x174); table_checksum(fadt); } else { printf("ERROR: no FADT yet?\n"); } hdr = COPYT(hdr); break; } default: hdr = COPYT(hdr); } table_checksum(hdr); xsdt->table_addr[i] = rsdt->table_addr[i] = B2P(hdr); } xsdt->table_addr[i] = rsdt->table_addr[i] = B2P(p); i++; p = build_ivrs(p); rsdt->hdr.length = sizeof(*rsdt) + 4 * i; xsdt->hdr.length = sizeof(*xsdt) + 8 * i; rsdp_checksum(rsdp); table_checksum(rsdt); table_checksum(xsdt); memcpy(map_base, buf_base, p - buf_base); }