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
);
105 struct grub_env_var
*var
;
107 /* Copy to definitive loaction */
108 grub_dprintf ("efiemu", "preparing pnvram\n");
110 env
= grub_env_get ("EfiEmu.pnvram.high_monotonic_count");
111 *high_monotonic_count
= env
? grub_strtoul (env
, 0, 0) : 1;
112 env
= grub_env_get ("EfiEmu.pnvram.timezone");
113 *timezone
= env
? grub_strtosl (env
, 0, 0) : GRUB_EFI_UNSPECIFIED_TIMEZONE
;
114 env
= grub_env_get ("EfiEmu.pnvram.accuracy");
115 *accuracy
= env
? grub_strtoul (env
, 0, 0) : 50000000;
116 env
= grub_env_get ("EfiEmu.pnvram.daylight");
117 *daylight
= env
? grub_strtoul (env
, 0, 0) : 0;
120 grub_memset (nvram
, 0, nvramsize
);
123 char *guid
, *attr
, *name
, *varname
;
124 struct efi_variable
*efivar
;
127 grub_uint64_t guidcomp
;
129 if (grub_memcmp (var
->name
, "EfiEmu.pnvram.",
130 sizeof ("EfiEmu.pnvram.") - 1) != 0)
133 guid
= var
->name
+ sizeof ("EfiEmu.pnvram.") - 1;
135 attr
= grub_strchr (guid
, '.');
140 name
= grub_strchr (attr
, '.');
145 efivar
= (struct efi_variable
*) nvramptr
;
146 if (nvramptr
- nvram
+ sizeof (struct efi_variable
) > nvramsize
)
147 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
148 "too many NVRAM variables for reserved variable space."
149 " Try increasing EfiEmu.pnvram.size");
151 nvramptr
+= sizeof (struct efi_variable
);
153 efivar
->guid
.data1
= grub_cpu_to_le32 (grub_strtoul (guid
, &guid
, 16));
158 efivar
->guid
.data2
= grub_cpu_to_le16 (grub_strtoul (guid
, &guid
, 16));
163 efivar
->guid
.data3
= grub_cpu_to_le16 (grub_strtoul (guid
, &guid
, 16));
168 guidcomp
= grub_strtoull (guid
, 0, 16);
169 for (i
= 0; i
< 8; i
++)
170 efivar
->guid
.data4
[i
] = (guidcomp
>> (56 - 8 * i
)) & 0xff;
172 efivar
->attributes
= grub_strtoull (attr
, 0, 16);
174 varname
= grub_malloc (grub_strlen (name
) + 1);
178 if (unescape (name
, varname
, varname
+ grub_strlen (name
) + 1, &len
))
181 len
= grub_utf8_to_utf16 ((grub_uint16_t
*) nvramptr
,
182 (nvramsize
- (nvramptr
- nvram
)) / 2,
183 (grub_uint8_t
*) varname
, len
, NULL
);
186 *((grub_uint16_t
*) nvramptr
) = 0;
188 efivar
->namelen
= 2 * len
+ 2;
190 if (unescape (var
->value
, nvramptr
, nvram
+ nvramsize
, &len
))
203 *nvramsize_def
= nvramsize
;
205 /* Register symbols */
206 grub_efiemu_register_symbol ("efiemu_variables", nvram_handle
, 0);
207 grub_efiemu_register_symbol ("efiemu_varsize", nvramsize_handle
, 0);
208 grub_efiemu_register_symbol ("efiemu_high_monotonic_count",
209 high_monotonic_count_handle
, 0);
210 grub_efiemu_register_symbol ("efiemu_time_zone", timezone_handle
, 0);
211 grub_efiemu_register_symbol ("efiemu_time_daylight", daylight_handle
, 0);
212 grub_efiemu_register_symbol ("efiemu_time_accuracy",
215 return GRUB_ERR_NONE
;
219 nvram_unload (void * data
__attribute__ ((unused
)))
221 grub_efiemu_mm_return_request (nvram_handle
);
222 grub_efiemu_mm_return_request (nvramsize_handle
);
223 grub_efiemu_mm_return_request (high_monotonic_count_handle
);
224 grub_efiemu_mm_return_request (timezone_handle
);
225 grub_efiemu_mm_return_request (accuracy_handle
);
226 grub_efiemu_mm_return_request (daylight_handle
);
230 grub_efiemu_pnvram (void)
237 size
= grub_env_get ("EfiEmu.pnvram.size");
239 nvramsize
= grub_strtoul (size
, 0, 0);
244 err
= grub_efiemu_register_prepare_hook (nvram_set
, nvram_unload
, 0);
249 = grub_efiemu_request_memalign (1, nvramsize
,
250 GRUB_EFI_RUNTIME_SERVICES_DATA
);
252 = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t
),
253 GRUB_EFI_RUNTIME_SERVICES_DATA
);
254 high_monotonic_count_handle
255 = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t
),
256 GRUB_EFI_RUNTIME_SERVICES_DATA
);
258 = grub_efiemu_request_memalign (1, sizeof (grub_uint16_t
),
259 GRUB_EFI_RUNTIME_SERVICES_DATA
);
261 = grub_efiemu_request_memalign (1, sizeof (grub_uint8_t
),
262 GRUB_EFI_RUNTIME_SERVICES_DATA
);
264 = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t
),
265 GRUB_EFI_RUNTIME_SERVICES_DATA
);
267 return GRUB_ERR_NONE
;