xref: /netbsd-src/sys/stand/efiboot/efiacpi.c (revision eceb233b9bd0dfebb902ed73b531ae6964fa3f9b)
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