34
35
static int accuracy_handle = 0;
35
36
static int daylight_handle = 0;
38
static grub_uint8_t *nvram;
39
38
static grub_size_t nvramsize;
40
static grub_uint32_t high_monotonic_count;
41
static grub_int16_t timezone;
42
static grub_uint8_t daylight;
43
static grub_uint32_t accuracy;
45
static const struct grub_arg_option options[] = {
46
{"size", 's', 0, "number of bytes to reserve for pseudo NVRAM", 0,
48
{"high-monotonic-count", 'm', 0,
49
"Initial value of high monotonic count", 0, ARG_TYPE_INT},
51
"Timezone, offset in minutes from GMT", 0, ARG_TYPE_INT},
53
"Accuracy of clock, in 1e-12 units", 0, ARG_TYPE_INT},
55
"Daylight value, as per EFI specifications", 0, ARG_TYPE_INT},
59
40
/* Parse signed value */
61
grub_strtosl (char *arg, char **end, int base)
42
grub_strtosl (const char *arg, char **end, int base)
64
45
return -grub_strtoul (arg + 1, end, base);
65
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");
68
87
/* Export stuff for efiemu */
70
89
nvram_set (void * data __attribute__ ((unused)))
72
92
/* Take definitive pointers */
73
grub_uint8_t *nvram_def = grub_efiemu_mm_obtain_request (nvram_handle);
93
char *nvram = grub_efiemu_mm_obtain_request (nvram_handle);
74
94
grub_uint32_t *nvramsize_def
75
95
= grub_efiemu_mm_obtain_request (nvramsize_handle);
76
grub_uint32_t *high_monotonic_count_def
96
grub_uint32_t *high_monotonic_count
77
97
= grub_efiemu_mm_obtain_request (high_monotonic_count_handle);
78
grub_int16_t *timezone_def
98
grub_int16_t *timezone
79
99
= grub_efiemu_mm_obtain_request (timezone_handle);
80
grub_uint8_t *daylight_def
100
grub_uint8_t *daylight
81
101
= grub_efiemu_mm_obtain_request (daylight_handle);
82
grub_uint32_t *accuracy_def
102
grub_uint32_t *accuracy
83
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))
85
198
/* Copy to definitive loaction */
86
199
grub_dprintf ("efiemu", "preparing pnvram\n");
87
grub_memcpy (nvram_def, nvram, nvramsize);
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);
88
215
*nvramsize_def = nvramsize;
89
*high_monotonic_count_def = high_monotonic_count;
90
*timezone_def = timezone;
91
*daylight_def = daylight;
92
*accuracy_def = accuracy;
94
217
/* Register symbols */
95
218
grub_efiemu_register_symbol ("efiemu_variables", nvram_handle, 0);
113
236
grub_efiemu_mm_return_request (timezone_handle);
114
237
grub_efiemu_mm_return_request (accuracy_handle);
115
238
grub_efiemu_mm_return_request (daylight_handle);
121
/* Load the variables file It's in format
122
guid1:attr1:name1:data1;
123
guid2:attr2:name2:data2;
125
Where all fields are in hex
128
read_pnvram (char *filename)
130
char *buf, *ptr, *ptr2;
133
grub_uint8_t *nvramptr = nvram;
134
struct efi_variable *efivar;
135
grub_size_t guidlen, datalen;
138
file = grub_file_open (filename);
140
return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram");
141
size = grub_file_size (file);
142
buf = grub_malloc (size + 1);
144
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read pnvram");
145
if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
146
return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram");
148
grub_file_close (file);
150
for (ptr = buf; *ptr; )
152
if (grub_isspace (*ptr))
158
efivar = (struct efi_variable *) nvramptr;
159
if (nvramptr - nvram + sizeof (struct efi_variable) > nvramsize)
160
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
161
"file is too large for reserved variable space");
163
nvramptr += sizeof (struct efi_variable);
165
/* look ahow long guid field is*/
167
for (ptr2 = ptr; (grub_isspace (*ptr2)
168
|| (*ptr2 >= '0' && *ptr2 <= '9')
169
|| (*ptr2 >= 'a' && *ptr2 <= 'f')
170
|| (*ptr2 >= 'A' && *ptr2 <= 'F'));
172
if (!grub_isspace (*ptr2))
177
if (guidlen != sizeof (efivar->guid))
180
return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
182
for (i = 0; i < 2 * sizeof (efivar->guid); i++)
185
while (grub_isspace (*ptr))
187
if (*ptr >= '0' && *ptr <= '9')
189
if (*ptr >= 'a' && *ptr <= 'f')
190
hex = *ptr - 'a' + 10;
191
if (*ptr >= 'A' && *ptr <= 'F')
192
hex = *ptr - 'A' + 10;
195
((grub_uint8_t *)&(efivar->guid))[i/2] = hex << 4;
197
((grub_uint8_t *)&(efivar->guid))[i/2] |= hex;
201
while (grub_isspace (*ptr))
205
grub_dprintf ("efiemu", "Not colon\n");
207
return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
210
while (grub_isspace (*ptr))
213
/* Attributes can be just parsed by existing functions */
214
efivar->attributes = grub_strtoul (ptr, &ptr, 16);
216
while (grub_isspace (*ptr))
220
grub_dprintf ("efiemu", "Not colon\n");
222
return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
225
while (grub_isspace (*ptr))
228
/* Read name and value */
229
for (j = 0; j < 2; j++)
231
/* Look the length */
233
for (ptr2 = ptr; *ptr2 && (grub_isspace (*ptr2)
234
|| (*ptr2 >= '0' && *ptr2 <= '9')
235
|| (*ptr2 >= 'a' && *ptr2 <= 'f')
236
|| (*ptr2 >= 'A' && *ptr2 <= 'F'));
238
if (!grub_isspace (*ptr2))
242
if (nvramptr - nvram + datalen > nvramsize)
245
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
246
"file is too large for reserved "
250
for (i = 0; i < 2 * datalen; i++)
253
while (grub_isspace (*ptr))
255
if (*ptr >= '0' && *ptr <= '9')
257
if (*ptr >= 'a' && *ptr <= 'f')
258
hex = *ptr - 'a' + 10;
259
if (*ptr >= 'A' && *ptr <= 'F')
260
hex = *ptr - 'A' + 10;
263
nvramptr[i/2] = hex << 4;
265
nvramptr[i/2] |= hex;
269
while (grub_isspace (*ptr))
271
if (*ptr != (j ? ';' : ':'))
274
grub_dprintf ("efiemu", j?"Not semicolon\n":"Not colon\n");
275
return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
278
efivar->size = datalen;
280
efivar->namelen = datalen;
286
return GRUB_ERR_NONE;
290
grub_efiemu_make_nvram (void)
242
grub_efiemu_pnvram (void)
294
err = grub_efiemu_autocore ();
249
size = grub_env_get ("EfiEmu.pnvram.size");
251
nvramsize = grub_strtoul (size, 0, 0);
301
256
err = grub_efiemu_register_prepare_hook (nvram_set, nvram_unload, 0);
308
261
= grub_efiemu_request_memalign (1, nvramsize,
309
262
GRUB_EFI_RUNTIME_SERVICES_DATA);
323
276
= grub_efiemu_request_memalign (1, sizeof (grub_uint32_t),
324
277
GRUB_EFI_RUNTIME_SERVICES_DATA);
326
grub_efiemu_request_symbols (6);
327
279
return GRUB_ERR_NONE;
331
grub_efiemu_pnvram (void)
334
return GRUB_ERR_NONE;
337
high_monotonic_count = 1;
338
timezone = GRUB_EFI_UNSPECIFIED_TIMEZONE;
342
nvram = grub_zalloc (nvramsize);
344
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
345
"Couldn't allocate space for temporary pnvram storage");
347
return grub_efiemu_make_nvram ();
351
grub_cmd_efiemu_pnvram (struct grub_extcmd *cmd,
352
int argc, char **args)
354
struct grub_arg_list *state = cmd->state;
358
return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one argument expected");
360
nvramsize = state[0].set ? grub_strtoul (state[0].arg, 0, 0) : 2048;
361
high_monotonic_count = state[1].set ? grub_strtoul (state[1].arg, 0, 0) : 1;
362
timezone = state[2].set ? grub_strtosl (state[2].arg, 0, 0)
363
: GRUB_EFI_UNSPECIFIED_TIMEZONE;
364
accuracy = state[3].set ? grub_strtoul (state[3].arg, 0, 0) : 50000000;
365
daylight = state[4].set ? grub_strtoul (state[4].arg, 0, 0) : 0;
367
nvram = grub_zalloc (nvramsize);
369
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
370
"Couldn't allocate space for temporary pnvram storage");
372
if (argc == 1 && (err = read_pnvram (args[0])))
377
return grub_efiemu_make_nvram ();
380
static grub_extcmd_t cmd;
382
void grub_efiemu_pnvram_cmd_register (void);
383
void grub_efiemu_pnvram_cmd_unregister (void);
386
grub_efiemu_pnvram_cmd_register (void)
388
cmd = grub_register_extcmd ("efiemu_pnvram", grub_cmd_efiemu_pnvram,
389
GRUB_COMMAND_FLAG_BOTH,
390
"efiemu_pnvram [FILENAME]",
391
"Initialise pseudo-NVRAM and load variables "
397
grub_efiemu_pnvram_cmd_unregister (void)
399
grub_unregister_extcmd (cmd);