1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2016 Tooams Soome <tsoome@me.com> 14 */ 15 16 #include <sys/cdefs.h> 17 18 #include <stand.h> 19 #include <sys/stdint.h> 20 #include <machine/stdarg.h> 21 #include <bootstrap.h> 22 #include <efi.h> 23 #include <efilib.h> 24 #include <Guid/Acpi.h> 25 26 #include "platform/acfreebsd.h" 27 #include "acconfig.h" 28 #define ACPI_SYSTEM_XFACE 29 #include "actypes.h" 30 #include "actbl.h" 31 32 ACPI_TABLE_RSDP *rsdp; 33 EFI_GUID gEfiAcpiTableGuid = ACPI_TABLE_GUID; 34 EFI_GUID gEfiAcpi20TableGuid = EFI_ACPI_TABLE_GUID; 35 36 static void * 37 acpi_map_sdt(vm_offset_t addr) 38 { 39 /* PA == VA */ 40 return ((void *)addr); 41 } 42 43 static uint8_t 44 acpi_checksum(const void *p, size_t length) 45 { 46 const uint8_t *bp; 47 uint8_t sum; 48 49 bp = p; 50 sum = 0; 51 while (length--) 52 sum += *bp++; 53 54 return (sum); 55 } 56 57 /* 58 * We have duplication there, the same implementation is also 59 * in libi386/biosacpi.c. We will address this duplication later. 60 */ 61 void * 62 acpi_find_table(const char *sig) 63 { 64 uint_t entries, i; 65 ACPI_TABLE_HEADER *sdp; 66 ACPI_TABLE_RSDT *rsdt; 67 ACPI_TABLE_XSDT *xsdt; 68 69 if (rsdp == NULL) 70 return (NULL); 71 72 /* 73 * Note, we need to check both address value and size there, 74 * as 32-bit code can not access 64-bit address space. 75 */ 76 if (rsdp->Revision >= 2 && 77 rsdp->XsdtPhysicalAddress != 0 && 78 rsdp->XsdtPhysicalAddress < UINTPTR_MAX) { 79 xsdt = acpi_map_sdt(rsdp->XsdtPhysicalAddress); 80 sdp = (ACPI_TABLE_HEADER *)xsdt; 81 if (sdp->Length < sizeof (ACPI_TABLE_HEADER)) { 82 entries = 0; 83 } else { 84 entries = sdp->Length - sizeof (ACPI_TABLE_HEADER); 85 entries /= ACPI_XSDT_ENTRY_SIZE; 86 } 87 for (i = 0; i < entries; i++) { 88 if (xsdt->TableOffsetEntry[i] == 0 || 89 xsdt->TableOffsetEntry[i] >= UINTPTR_MAX) 90 continue; 91 sdp = acpi_map_sdt(xsdt->TableOffsetEntry[i]); 92 if (sdp->Length < sizeof (ACPI_TABLE_HEADER)) 93 continue; 94 95 if (acpi_checksum(sdp, sdp->Length)) 96 continue; 97 98 if (ACPI_COMPARE_NAME(sig, sdp->Signature)) 99 return (sdp); 100 } 101 } 102 103 if (rsdp->RsdtPhysicalAddress != 0) { 104 rsdt = acpi_map_sdt(rsdp->RsdtPhysicalAddress); 105 sdp = (ACPI_TABLE_HEADER *)rsdt; 106 if (sdp->Length < sizeof (ACPI_TABLE_HEADER)) { 107 entries = 0; 108 } else { 109 entries = sdp->Length - sizeof (ACPI_TABLE_HEADER); 110 entries /= ACPI_RSDT_ENTRY_SIZE; 111 } 112 for (i = 0; i < entries; i++) { 113 if (rsdt->TableOffsetEntry[i] == 0) 114 continue; 115 sdp = acpi_map_sdt(rsdt->TableOffsetEntry[i]); 116 if (sdp->Length < sizeof (ACPI_TABLE_HEADER)) 117 continue; 118 119 if (acpi_checksum(sdp, sdp->Length)) 120 continue; 121 122 if (ACPI_COMPARE_NAME(sig, sdp->Signature)) 123 return (sdp); 124 } 125 } 126 return (NULL); 127 } 128 129 void 130 acpi_detect(void) 131 { 132 char buf[24]; 133 int revision; 134 135 if ((rsdp = efi_get_table(&gEfiAcpi20TableGuid)) == NULL) 136 rsdp = efi_get_table(&gEfiAcpiTableGuid); 137 138 if (rsdp == NULL) 139 return; 140 141 /* export values from the RSDP */ 142 #ifdef _LP64 143 snprintf(buf, sizeof (buf), "0x%016llx", (unsigned long long)rsdp); 144 #else 145 snprintf(buf, sizeof (buf), "0x%08x", (unsigned int)rsdp); 146 #endif 147 setenv("acpi.rsdp", buf, 1); 148 revision = rsdp->Revision; 149 if (revision == 0) 150 revision = 1; 151 snprintf(buf, sizeof (buf), "%d", revision); 152 setenv("acpi.revision", buf, 1); 153 strncpy(buf, rsdp->OemId, sizeof (rsdp->OemId)); 154 buf[sizeof (rsdp->OemId)] = '\0'; 155 setenv("acpi.oem", buf, 1); 156 #ifdef _LP64 157 snprintf(buf, sizeof (buf), "0x%016llx", 158 (unsigned long long)rsdp->RsdtPhysicalAddress); 159 #else 160 snprintf(buf, sizeof (buf), "0x%08x", rsdp->RsdtPhysicalAddress); 161 #endif 162 setenv("acpi.rsdt", buf, 1); 163 if (revision >= 2) { 164 snprintf(buf, sizeof (buf), "0x%016llx", 165 (unsigned long long)rsdp->XsdtPhysicalAddress); 166 setenv("acpi.xsdt", buf, 1); 167 snprintf(buf, sizeof (buf), "%d", rsdp->Length); 168 setenv("acpi.xsdt_length", buf, 1); 169 } 170 } 171