]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/efi/libefi/env.c
MFC r307322,r307323,r307324,r307326,r307327,r307338,r307879,r307908,r307911,
[FreeBSD/FreeBSD.git] / sys / boot / efi / libefi / env.c
1 /*
2  * Copyright (c) 2015 Netflix, Inc. All Rights Reserved.
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 AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE 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
19  * OR 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 __FBSDID("$FreeBSD$");
28
29 #include <stand.h>
30 #include <string.h>
31 #include <efi.h>
32 #include <efilib.h>
33 #include <uuid.h>
34 #include "bootstrap.h"
35 #include "ficl.h"
36
37 int efi_variable_support = 1;
38
39 /*
40  * Simple wrappers to the underlying UEFI functions.
41  * See http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES
42  * for details.
43  */
44 EFI_STATUS
45 efi_get_next_variable_name(UINTN *variable_name_size, CHAR16 *variable_name, EFI_GUID *vendor_guid)
46 {
47         return RS->GetNextVariableName(variable_name_size, variable_name, vendor_guid);
48 }
49
50 EFI_STATUS
51 efi_get_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, UINT32 *attributes, UINTN *data_size,
52     void *data)
53 {
54         return RS->GetVariable(variable_name, vendor_guid, attributes, data_size, data);
55 }
56
57 EFI_STATUS
58 efi_set_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, UINT32 attributes, UINTN data_size,
59     void *data)
60 {
61         return RS->SetVariable(variable_name, vendor_guid, attributes, data_size, data);
62 }
63
64 /*
65  *              FreeBSD's loader interaction words and extras
66  *
67  *              efi-setenv  ( value n name n guid n attr -- 0 | -1)
68  *              efi-getenv  ( guid n addr n -- addr' n' | -1 )
69  *              efi-unsetenv ( name n guid n'' -- )
70  */
71
72 /*
73  * efi-setenv
74  *              efi-setenv  ( value n name n guid n attr -- 0 | -1)
75  *
76  * Set environment variables using the SetVariable EFI runtime service.
77  *
78  * Value and guid are passed through in binary form (so guid needs to be
79  * converted to binary form from its string form). Name is converted from
80  * ASCII to CHAR16. Since ficl doesn't have support for internationalization,
81  * there's no native CHAR16 interface provided.
82  *
83  * attr is an int in the bitmask of the following attributes for this variable.
84  *
85  *      1       Non volatile
86  *      2       Boot service access
87  *      4       Run time access
88  * (corresponding to the same bits in the UEFI spec).
89  */
90 void
91 ficlEfiSetenv(FICL_VM *pVM)
92 {
93 #ifndef TESTMAIN
94         char    *value = NULL, *guid = NULL;
95         CHAR16  *name = NULL;
96         int     i;
97 #endif
98         char    *namep, *valuep, *guidp;
99         int     names, values, guids, attr;
100         int     status;
101         uuid_t  u;
102         uint32_t ustatus;
103
104 #if FICL_ROBUST > 1
105         vmCheckStack(pVM, 6, 0);
106 #endif
107         attr = stackPopINT(pVM->pStack);
108         guids = stackPopINT(pVM->pStack);
109         guidp = (char*)stackPopPtr(pVM->pStack);
110         names = stackPopINT(pVM->pStack);
111         namep = (char*)stackPopPtr(pVM->pStack);
112         values = stackPopINT(pVM->pStack);
113         valuep = (char*)stackPopPtr(pVM->pStack);
114
115 #ifndef TESTMAIN
116         guid = (char*)ficlMalloc(guids);
117         if (guid == NULL)
118                 vmThrowErr(pVM, "Error: out of memory");
119         memcpy(guid, guidp, guids);
120         uuid_from_string(guid, &u, &ustatus);
121         if (ustatus != uuid_s_ok) {
122                 stackPushINT(pVM->pStack, -1);
123                 goto out;
124         }
125
126         name = (CHAR16 *)ficlMalloc((names + 1) * sizeof(CHAR16));
127         if (name == NULL)
128                 vmThrowErr(pVM, "Error: out of memory");
129         for (i = 0; i < names; i++)
130                 name[i] = namep[i];
131         name[names] = (CHAR16)0;
132
133         value = (char*)ficlMalloc(values + 1);
134         if (value == NULL)
135                 vmThrowErr(pVM, "Error: out of memory");
136         memcpy(value, valuep, values);
137
138         status = efi_set_variable(name, (EFI_GUID *)&u, attr, values, value);
139         if (status == EFI_SUCCESS)
140                 stackPushINT(pVM->pStack, 0);
141         else
142                 stackPushINT(pVM->pStack, -1);
143 out:
144         ficlFree(name);
145         ficlFree(value);
146         ficlFree(guid);
147 #endif
148
149         return;
150 }
151
152 void
153 ficlEfiGetenv(FICL_VM *pVM)
154 {
155 #ifndef TESTMAIN
156         char    *name, *value;
157 #endif
158         char    *namep;
159         int     names;
160
161 #if FICL_ROBUST > 1
162         vmCheckStack(pVM, 2, 2);
163 #endif
164         names = stackPopINT(pVM->pStack);
165         namep = (char*) stackPopPtr(pVM->pStack);
166
167 #ifndef TESTMAIN
168         name = (char*) ficlMalloc(names+1);
169         if (name == NULL)
170                 vmThrowErr(pVM, "Error: out of memory");
171         strncpy(name, namep, names);
172         name[names] = '\0';
173
174         value = getenv(name);
175         ficlFree(name);
176
177         if(value != NULL) {
178                 stackPushPtr(pVM->pStack, value);
179                 stackPushINT(pVM->pStack, strlen(value));
180         } else
181 #endif
182                 stackPushINT(pVM->pStack, -1);
183
184         return;
185 }
186
187 void
188 ficlEfiUnsetenv(FICL_VM *pVM)
189 {
190 #ifndef TESTMAIN
191         char    *name;
192 #endif
193         char    *namep;
194         int     names;
195
196 #if FICL_ROBUST > 1
197         vmCheckStack(pVM, 2, 0);
198 #endif
199         names = stackPopINT(pVM->pStack);
200         namep = (char*) stackPopPtr(pVM->pStack);
201
202 #ifndef TESTMAIN
203         name = (char*) ficlMalloc(names+1);
204         if (name == NULL)
205                 vmThrowErr(pVM, "Error: out of memory");
206         strncpy(name, namep, names);
207         name[names] = '\0';
208
209         unsetenv(name);
210         ficlFree(name);
211 #endif
212
213         return;
214 }
215
216 /**************************************************************************
217 ** Add FreeBSD UEFI platform extensions into the system dictionary
218 **************************************************************************/
219 void ficlEfiCompilePlatform(FICL_SYSTEM *pSys)
220 {
221     FICL_DICT *dp = pSys->dp;
222     assert (dp);
223
224     dictAppendWord(dp, "efi-setenv",    ficlEfiSetenv,      FW_DEFAULT);
225     dictAppendWord(dp, "efi-getenv",    ficlEfiGetenv,      FW_DEFAULT);
226     dictAppendWord(dp, "efi-unsetenv",  ficlEfiUnsetenv,    FW_DEFAULT);
227
228     /* Would like to export the EFI version, but this will do for now */
229     ficlSetEnv(pSys, "efi-boot", 1);
230
231     return;
232 }
233
234 FICL_COMPILE_SET(ficlEfiCompilePlatform);