1 /* $NetBSD: efiacpi.c,v 1.7 2020/05/14 19:19:08 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jared McNeill <jmcneill@invisible.ca>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "efiboot.h" 33 #include "efiacpi.h" 34 #include "efifdt.h" 35 #include "smbios.h" 36 37 struct acpi_rdsp { 38 char signature[8]; 39 uint8_t checksum; 40 char oemid[6]; 41 uint8_t revision; 42 uint32_t rsdtphys; 43 uint32_t length; 44 uint64_t xsdtphys; 45 uint8_t extcsum; 46 uint8_t reserved[3]; 47 }; 48 49 #include <libfdt.h> 50 51 #define ACPI_FDT_SIZE (128 * 1024) 52 53 static EFI_GUID Acpi20TableGuid = ACPI_20_TABLE_GUID; 54 static EFI_GUID Smbios3TableGuid = SMBIOS3_TABLE_GUID; 55 56 static void *acpi_root = NULL; 57 static void *smbios3_table = NULL; 58 59 int 60 efi_acpi_probe(void) 61 { 62 EFI_STATUS status; 63 64 status = LibGetSystemConfigurationTable(&Acpi20TableGuid, &acpi_root); 65 if (EFI_ERROR(status)) 66 return EIO; 67 68 status = LibGetSystemConfigurationTable(&Smbios3TableGuid, &smbios3_table); 69 if (EFI_ERROR(status)) 70 smbios3_table = NULL; 71 72 return 0; 73 } 74 75 int 76 efi_acpi_available(void) 77 { 78 return acpi_root != NULL; 79 } 80 81 static char model_buf[128]; 82 83 static const char * 84 efi_acpi_get_model(void) 85 { 86 struct smbtable smbios; 87 struct smbios_sys *psys; 88 const char *s; 89 char *buf; 90 91 memset(model_buf, 0, sizeof(model_buf)); 92 93 if (smbios3_table != NULL) { 94 smbios_init(smbios3_table); 95 96 buf = model_buf; 97 smbios.cookie = 0; 98 if (smbios_find_table(SMBIOS_TYPE_SYSTEM, &smbios)) { 99 psys = smbios.tblhdr; 100 if ((s = smbios_get_string(&smbios, psys->vendor, buf, 64)) != NULL) { 101 buf += strlen(s); 102 *buf++ = ' '; 103 } 104 smbios_get_string(&smbios, psys->product, buf, 64); 105 } 106 } 107 108 if (model_buf[0] == '\0') 109 strcpy(model_buf, "ACPI"); 110 111 return model_buf; 112 } 113 114 void 115 efi_acpi_show(void) 116 { 117 struct acpi_rdsp *rsdp = acpi_root; 118 119 if (!efi_acpi_available()) 120 return; 121 122 printf("ACPI: v%02d %c%c%c%c%c%c\n", rsdp->revision, 123 rsdp->oemid[0], rsdp->oemid[1], rsdp->oemid[2], 124 rsdp->oemid[3], rsdp->oemid[4], rsdp->oemid[5]); 125 126 if (smbios3_table) 127 printf("SMBIOS: %s\n", efi_acpi_get_model()); 128 } 129 130 int 131 efi_acpi_create_fdt(void) 132 { 133 int error; 134 void *fdt; 135 136 if (acpi_root == NULL) 137 return EINVAL; 138 139 fdt = AllocatePool(ACPI_FDT_SIZE); 140 if (fdt == NULL) 141 return ENOMEM; 142 143 error = fdt_create_empty_tree(fdt, ACPI_FDT_SIZE); 144 if (error) 145 return EIO; 146 147 const char *model = efi_acpi_get_model(); 148 149 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "compatible", "netbsd,generic-acpi"); 150 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", model); 151 fdt_setprop_cell(fdt, fdt_path_offset(fdt, "/"), "#address-cells", 2); 152 fdt_setprop_cell(fdt, fdt_path_offset(fdt, "/"), "#size-cells", 2); 153 154 fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "chosen"); 155 fdt_setprop_u64(fdt, fdt_path_offset(fdt, "/chosen"), "netbsd,acpi-root-table", (uint64_t)(uintptr_t)acpi_root); 156 if (smbios3_table) 157 fdt_setprop_u64(fdt, fdt_path_offset(fdt, "/chosen"), "netbsd,smbios-table", (uint64_t)(uintptr_t)smbios3_table); 158 #ifdef EFIBOOT_RUNTIME_ADDRESS 159 fdt_setprop_u64(fdt, fdt_path_offset(fdt, "/chosen"), "netbsd,uefi-system-table", (uint64_t)(uintptr_t)ST); 160 #endif 161 162 fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "acpi"); 163 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/acpi"), "compatible", "netbsd,acpi"); 164 165 return efi_fdt_set_data(fdt); 166 } 167