1 /* Export pnvram and some variables for runtime */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/file.h>
22 #include <grub/normal.h>
24 #include <grub/misc.h>
25 #include <grub/charset.h>
26 #include <grub/efiemu/efiemu.h>
27 #include <grub/efiemu/runtime.h>
28 #include <grub/extcmd.h>
30 /* Place for final location of variables */
31 static int nvram_handle
= 0;
32 static int nvramsize_handle
= 0;
33 static int high_monotonic_count_handle
= 0;
34 static int timezone_handle
= 0;
35 static int accuracy_handle
= 0;
36 static int daylight_handle
= 0;
38 static grub_size_t nvramsize
;
40 /* Parse signed value */
42 grub_strtosl (const char *arg
, char **end
, int base
)
45 return -grub_strtoul (arg
+ 1, end
, base
);
46 return grub_strtoul (arg
, end
, base
);
52 if (c
>= '0' && c
<= '9')
54 if (c
>= 'a' && c
<= 'z')
56 if (c
>= 'A' && c
<= 'Z')
61 static inline grub_err_t
62 unescape (char *in
, char *out
, char *outmax
, int *len
)
66 for (ptr
= in
; *ptr
&& dptr
< outmax
; )
67 if (*ptr
== '%' && ptr
[1] && ptr
[2])
69 *dptr
= (hextoval (ptr
[1]) << 4) | (hextoval (ptr
[2]));
80 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
81 "too many NVRAM variables for reserved variable space."
82 " Try increasing EfiEmu.pnvram.size");
87 /* Export stuff for efiemu */
89 nvram_set (void * data
__attribute__ ((unused
)))
92 /* Take definitive pointers */
93 char *nvram
= grub_efiemu_mm_obtain_request (nvram_handle
);
94 grub_uint32_t
*nvramsize_def
95 = grub_efiemu_mm_obtain_request (nvramsize_handle
);
96 grub_uint32_t
*high_monotonic_count
97 = grub_efiemu_mm_obtain_request (high_monotonic_count_handle
);
98 grub_int16_t
*timezone
99 = grub_efiemu_mm_obtain_request (timezone_handle
);
100 grub_uint8_t
*daylight
101 = grub_efiemu_mm_obtain_request (daylight_handle
);
102 grub_uint32_t
*accuracy
103 = grub_efiemu_mm_obtain_request (accuracy_handle
);
106 auto int iterate_env (struct grub_env_var
*var
);
107 int iterate_env (struct grub_env_var
*var
)
109 char *guid
, *attr
, *name
, *varname
;
110 struct efi_variable
*efivar
;
113 grub_uint64_t guidcomp
;
115 if (grub_memcmp (var
->name
, "EfiEmu.pnvram.",
116 sizeof ("EfiEmu.pnvram.") - 1) != 0)
119 guid
= var
->name
+ sizeof ("EfiEmu.pnvram.") - 1;
121 attr
= grub_strchr (guid
, '.');
126 name
= grub_strchr (attr
, '.');
131 efivar
= (struct efi_variable
*) nvramptr
;
132 if (nvramptr
- nvram
+ sizeof (struct efi_variable
) > nvramsize
)
134 grub_error (GRUB_ERR_OUT_OF_MEMORY
,
135 "too many NVRAM variables for reserved variable space."
136 " Try increasing EfiEmu.pnvram.size");
140 nvramptr
+= sizeof (struct efi_variable
);
142 efivar
->guid
.data1
= grub_cpu_to_le32 (grub_strtoul (guid
, &guid
, 16));
147 efivar
->guid
.data2
= grub_cpu_to_le16 (grub_strtoul (guid
, &guid
, 16));
152 efivar
->guid
.data3
= grub_cpu_to_le16 (grub_strtoul (guid
, &guid
, 16));
157 guidcomp
= grub_strtoull (guid
, 0, 16);
158 for (i
= 0; i
< 8; i
++)
159 efivar
->guid
.data4
[i
] = (guidcomp
>> (56 - 8 * i
)) & 0xff;
161 efivar
->attributes
= grub_strtoull (attr
, 0, 16);
163 varname
= grub_malloc (grub_strlen (name
) + 1);
167 if (unescape (name
, varname
, varname
+ grub_strlen (name
) + 1, &len
))
170 len
= grub_utf8_to_utf16 ((grub_uint16_t
*) nvramptr
,
171 (nvramsize
- (nvramptr
- nvram
)) / 2,
172 (grub_uint8_t
*) varname
, len
, NULL
);
176 grub_error (GRUB_ERR_BAD_ARGUMENT
, "broken UTF-8 in variable name");
181 *((grub_uint16_t
*) nvramptr
) = 0;
183 efivar
->namelen
= 2 * len
+ 2;
185 if (unescape (var
->value
, nvramptr
, nvram
+ nvramsize
, &len
))
198 /* Copy to definitive loaction */
199 grub_dprintf ("efiemu", "preparing pnvram\n");
201 env
= grub_env_get ("EfiEmu.pnvram.high_monotonic_count");
202 *high_monotonic_count
= env
? grub_strtoul (env
, 0, 0) : 1;
203 env
= grub_env_get ("EfiEmu.pnvram.timezone");
204 *timezone
= env
? grub_strtosl (env
, 0, 0) : GRUB_EFI_UNSPECIFIED_TIMEZONE
;
205 env
= grub_env_get ("EfiEmu.pnvram.accuracy");
206 *accuracy
= env
? grub_strtoul (env
, 0, 0) : 50000000;
207 env
= grub_env_get ("EfiEmu.pnvram.daylight");
208 *daylight
= env
? grub_strtoul (env
, 0, 0) : 0;
211 grub_memset (nvram
, 0, nvramsize
);
212 grub_env_iterate (iterate_env
);
215 *nvramsize_def
= nvramsize
;
217 /* Register symbols */
218 grub_efiemu_register_symbol ("efiemu_variables", nvram_handle
, 0);
219 grub_efiemu_register_symbol ("efiemu_varsize", nvramsize_handle
, 0);
220 grub_efiemu_register_symbol ("efiemu_high_monotonic_count",
221 high_monotonic_count_handle
, 0);
222 grub_efiemu_register_symbol ("efiemu_time_zone", timezone_handle
, 0);
223 grub_efiemu_register_symbol ("efiemu_time_daylight", daylight_handle
, 0);
224 grub_efiemu_register_symbol ("efiemu_time_accuracy",
227 return GRUB_ERR_NONE
;
231 nvram_unload (void * data
__attribute__ ((unused
)))
233 grub_efiemu_mm_return_request (nvram_handle
);
234 grub_efiemu_mm_return_request (nvramsize_handle
);
235 grub_efiemu_mm_return_request (high_monotonic_count_handle
);
236 grub_efiemu_mm_return_request (timezone_handle
);
237 grub_efiemu_mm_return_request (accuracy_handle
);
238 grub_efiemu_mm_return_request (daylight_handle
);
242 grub_efiemu_pnvram (void)
249 size
= grub_env_get ("EfiEmu.pnvram.size");
251 nvramsize
= grub_strtoul (size
, 0, 0);
256 err
= grub_efiemu_register_prepare_hook (nvram_set
, nvram_unload
, 0);
261 = grub_efiemu_request_memalign (1, nvramsize
,
262 GRUB_EFI_RUNTIME_SERVICES_DATA
);
264 = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t
),
265 GRUB_EFI_RUNTIME_SERVICES_DATA
);
266 high_monotonic_count_handle
267 = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t
),
268 GRUB_EFI_RUNTIME_SERVICES_DATA
);
270 = grub_efiemu_request_memalign (1, sizeof (grub_uint16_t
),
271 GRUB_EFI_RUNTIME_SERVICES_DATA
);
273 = grub_efiemu_request_memalign (1, sizeof (grub_uint8_t
),
274 GRUB_EFI_RUNTIME_SERVICES_DATA
);
276 = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t
),
277 GRUB_EFI_RUNTIME_SERVICES_DATA
);
279 return GRUB_ERR_NONE
;