efiacpi.c revision 1.9 1 /* $NetBSD: efiacpi.c,v 1.9 2021/05/21 21:53:15 jmcneill 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 (at) 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 int acpi_enable = 1;
57 static void *acpi_root = NULL;
58 static void *smbios3_table = NULL;
59
60 int
61 efi_acpi_probe(void)
62 {
63 EFI_STATUS status;
64
65 status = LibGetSystemConfigurationTable(&Acpi20TableGuid, &acpi_root);
66 if (EFI_ERROR(status))
67 return EIO;
68
69 status = LibGetSystemConfigurationTable(&Smbios3TableGuid, &smbios3_table);
70 if (EFI_ERROR(status))
71 smbios3_table = NULL;
72
73 return 0;
74 }
75
76 int
77 efi_acpi_available(void)
78 {
79 return acpi_root != NULL;
80 }
81
82 int
83 efi_acpi_enabled(void)
84 {
85 return acpi_enable;
86 }
87
88 void
89 efi_acpi_enable(int enable)
90 {
91 acpi_enable = enable;
92 }
93
94 static char model_buf[128];
95
96 static const char *
97 efi_acpi_get_model(void)
98 {
99 struct smbtable smbios;
100 struct smbios_sys *psys;
101 const char *s;
102 char *buf;
103
104 memset(model_buf, 0, sizeof(model_buf));
105
106 if (smbios3_table != NULL) {
107 smbios_init(smbios3_table);
108
109 buf = model_buf;
110 smbios.cookie = 0;
111 if (smbios_find_table(SMBIOS_TYPE_SYSTEM, &smbios)) {
112 psys = smbios.tblhdr;
113 if ((s = smbios_get_string(&smbios, psys->vendor, buf, 64)) != NULL) {
114 buf += strlen(s);
115 *buf++ = ' ';
116 }
117 smbios_get_string(&smbios, psys->product, buf, 64);
118 }
119 }
120
121 if (model_buf[0] == '\0')
122 strcpy(model_buf, "ACPI");
123
124 return model_buf;
125 }
126
127 void
128 efi_acpi_show(void)
129 {
130 struct acpi_rdsp *rsdp = acpi_root;
131
132 if (!efi_acpi_available())
133 return;
134
135 printf("ACPI: v%02d %c%c%c%c%c%c\n", rsdp->revision,
136 rsdp->oemid[0], rsdp->oemid[1], rsdp->oemid[2],
137 rsdp->oemid[3], rsdp->oemid[4], rsdp->oemid[5]);
138
139 if (smbios3_table)
140 printf("SMBIOS: %s\n", efi_acpi_get_model());
141 }
142
143 int
144 efi_acpi_create_fdt(void)
145 {
146 int error;
147 void *fdt;
148
149 if (acpi_root == NULL)
150 return EINVAL;
151
152 fdt = AllocatePool(ACPI_FDT_SIZE);
153 if (fdt == NULL)
154 return ENOMEM;
155
156 error = fdt_create_empty_tree(fdt, ACPI_FDT_SIZE);
157 if (error)
158 return EIO;
159
160 const char *model = efi_acpi_get_model();
161
162 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "compatible", "netbsd,generic-acpi");
163 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", model);
164 fdt_setprop_cell(fdt, fdt_path_offset(fdt, "/"), "#address-cells", 2);
165 fdt_setprop_cell(fdt, fdt_path_offset(fdt, "/"), "#size-cells", 2);
166
167 fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "chosen");
168 fdt_setprop_u64(fdt, fdt_path_offset(fdt, "/chosen"), "netbsd,acpi-root-table", (uint64_t)(uintptr_t)acpi_root);
169 if (smbios3_table)
170 fdt_setprop_u64(fdt, fdt_path_offset(fdt, "/chosen"), "netbsd,smbios-table", (uint64_t)(uintptr_t)smbios3_table);
171
172 fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "acpi");
173 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/acpi"), "compatible", "netbsd,acpi");
174
175 return efi_fdt_set_data(fdt);
176 }
177