efiio.c revision 1.2 1 /* $NetBSD: efiio.c,v 1.2 2025/03/02 00:03:41 riastradh Exp $ */
2
3 /*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
14 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 #ifndef lint
28 __RCSID("$NetBSD: efiio.c,v 1.2 2025/03/02 00:03:41 riastradh Exp $");
29 #endif /* not lint */
30
31 #include <sys/efiio.h>
32 #include <sys/ioctl.h>
33
34 #include <assert.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <util.h>
41
42 #include "defs.h"
43 #include "efiio.h"
44 #include "utils.h"
45
46 //******************************************************
47 // Variable Attributes
48 //******************************************************
49 #if 0 /* see sys/efiio.h */
50 struct efi_var_ioc {
51 uint16_t * name; /* vendor's variable name */
52 size_t namesize; /* size in bytes of the name buffer */
53 struct uuid vendor; /* unique identifier for vendor */
54 uint32_t attrib; /* variable attribute bitmask */
55 void * data; /* buffer containing variable data */
56 size_t datasize; /* size in bytes of the data buffer */
57 };
58 #endif
59
60 static int
61 xioctl(int fd, unsigned long request, void *buf)
62 {
63 int rv;
64
65 rv = ioctl(fd, request, buf);
66 if (rv == -1 && errno != ENOENT)
67 err(EXIT_FAILURE, "%s: ioctl", __func__);
68 return rv;
69 }
70
71 PUBLIC int
72 set_variable(int fd, struct efi_var_ioc *ev)
73 {
74
75 return ioctl(fd, EFIIOC_VAR_SET, ev);
76 }
77
78 static inline int
79 get_variable_core(int fd, struct efi_var_ioc *ev)
80 {
81
82 if (xioctl(fd, EFIIOC_VAR_GET, ev) == -1)
83 return -1;
84
85 ev->data = emalloc(ev->datasize);
86 xioctl(fd, EFIIOC_VAR_GET, ev);
87 return 0;
88 }
89
90 PUBLIC struct efi_var_ioc
91 get_variable(int fd, const char *name, struct uuid *vendor,
92 uint32_t attrib)
93 {
94 struct efi_var_ioc ev;
95
96 efi_var_init(&ev, name, vendor, attrib);
97 get_variable_core(fd, &ev);
98
99 return ev;
100 }
101
102 PUBLIC struct efi_var_ioc *
103 get_next_variable(int fd, struct efi_var_ioc *ev)
104 {
105 int rv;
106
107 rv = ioctl(fd, EFIIOC_VAR_NEXT, ev);
108 if (rv == -1 && errno != ENOENT)
109 err(EXIT_FAILURE, "%s: ioctl", __func__);
110 return ev;
111 }
112
113 PUBLIC void *
114 get_table(int fd, struct uuid *uuid, size_t *buflen)
115 {
116 struct efi_get_table_ioc egt;
117
118 memset(&egt, 0, sizeof(egt));
119 memcpy(&egt.uuid, uuid, sizeof(egt.uuid));
120
121 xioctl(fd, EFIIOC_GET_TABLE, &egt);
122 egt.buf = ecalloc(egt.table_len, 1);
123 egt.buf_len = egt.table_len;
124
125 xioctl(fd, EFIIOC_GET_TABLE, &egt);
126 *buflen = egt.table_len;
127 return egt.buf;
128 }
129
130 PUBLIC size_t
131 get_variable_info(int fd, bool (*choose)(struct efi_var_ioc *, void *),
132 int (*fn)(struct efi_var_ioc *ev, void *), void *arg)
133 {
134 struct efi_var_ioc ev;
135 size_t cnt;
136 int rv;
137
138 assert(fn != NULL);
139 assert(arg != NULL);
140
141 memset(&ev, 0, sizeof(ev));
142
143 ev.name = ecalloc(EFI_VARNAME_MAXLENGTH, sizeof(*ev.name));
144 cnt = 0;
145 for (;;) {
146 ev.namesize = EFI_VARNAME_MAXLENGTH;
147 if (ioctl(fd, EFIIOC_VAR_NEXT, &ev) == -1) {
148 char *buf;
149
150 if (errno == ENOENT)
151 break;
152
153 /* XXX: ev is likely to be zero */
154 buf = ucs2_to_utf8(ev.name, ev.namesize, NULL, NULL);
155 err(EXIT_FAILURE, "%s: '%s'", __func__, buf);
156 }
157
158 if (choose != NULL && !choose(&ev, arg))
159 continue;
160
161 rv = get_variable_core(fd, &ev);
162 assert(rv == 0);
163 if (rv == -1)
164 err(EXIT_FAILURE, "get_variable_core");
165
166 cnt++;
167 fn(&ev, arg);
168
169 free(ev.data);
170 }
171 free(ev.name);
172 return cnt;
173 }
174