pnvram.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /* Export pnvram and some variables for runtime */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2009 Free Software Foundation, Inc.
  5. *
  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.
  10. *
  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.
  15. *
  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/>.
  18. */
  19. #include <grub/file.h>
  20. #include <grub/err.h>
  21. #include <grub/normal.h>
  22. #include <grub/mm.h>
  23. #include <grub/env.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>
  29. /* Place for final location of variables */
  30. static int nvram_handle = 0;
  31. static int nvramsize_handle = 0;
  32. static int high_monotonic_count_handle = 0;
  33. static int timezone_handle = 0;
  34. static int accuracy_handle = 0;
  35. static int daylight_handle = 0;
  36. static grub_size_t nvramsize;
  37. /* Parse signed value */
  38. static int
  39. grub_strtosl (const char *arg, char **end, int base)
  40. {
  41. if (arg[0] == '-')
  42. return -grub_strtoul (arg + 1, end, base);
  43. return grub_strtoul (arg, end, base);
  44. }
  45. static inline int
  46. hextoval (char c)
  47. {
  48. if (c >= '0' && c <= '9')
  49. return c - '0';
  50. if (c >= 'a' && c <= 'z')
  51. return c - 'a' + 10;
  52. if (c >= 'A' && c <= 'Z')
  53. return c - 'A' + 10;
  54. return 0;
  55. }
  56. static inline grub_err_t
  57. unescape (char *in, char *out, char *outmax, int *len)
  58. {
  59. char *ptr, *dptr;
  60. dptr = out;
  61. for (ptr = in; *ptr && dptr < outmax; )
  62. if (*ptr == '%' && ptr[1] && ptr[2])
  63. {
  64. *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2]));
  65. ptr += 3;
  66. dptr++;
  67. }
  68. else
  69. {
  70. *dptr = *ptr;
  71. ptr++;
  72. dptr++;
  73. }
  74. if (dptr == outmax)
  75. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  76. "too many NVRAM variables for reserved variable space."
  77. " Try increasing EfiEmu.pnvram.size");
  78. *len = dptr - out;
  79. return 0;
  80. }
  81. struct nvram_set_closure
  82. {
  83. char *nvram;
  84. char *nvramptr;
  85. };
  86. static int
  87. iterate_env (struct grub_env_var *var, void *closure)
  88. {
  89. struct nvram_set_closure *c = closure;
  90. char *guid, *attr, *name, *varname;
  91. struct efi_variable *efivar;
  92. int len = 0;
  93. int i;
  94. grub_uint64_t guidcomp;
  95. if (grub_memcmp (var->name, "EfiEmu.pnvram.",
  96. sizeof ("EfiEmu.pnvram.") - 1) != 0)
  97. return 0;
  98. guid = var->name + sizeof ("EfiEmu.pnvram.") - 1;
  99. attr = grub_strchr (guid, '.');
  100. if (!attr)
  101. return 0;
  102. attr++;
  103. name = grub_strchr (attr, '.');
  104. if (!name)
  105. return 0;
  106. name++;
  107. efivar = (struct efi_variable *) c->nvramptr;
  108. if (c->nvramptr - c->nvram + sizeof (struct efi_variable) > nvramsize)
  109. {
  110. grub_error (GRUB_ERR_OUT_OF_MEMORY,
  111. "too many NVRAM variables for reserved variable space."
  112. " Try increasing EfiEmu.pnvram.size");
  113. return 1;
  114. }
  115. c->nvramptr += sizeof (struct efi_variable);
  116. efivar->guid.data1 = grub_cpu_to_le32 (grub_strtoul (guid, &guid, 16));
  117. if (*guid != '-')
  118. return 0;
  119. guid++;
  120. efivar->guid.data2 = grub_cpu_to_le16 (grub_strtoul (guid, &guid, 16));
  121. if (*guid != '-')
  122. return 0;
  123. guid++;
  124. efivar->guid.data3 = grub_cpu_to_le16 (grub_strtoul (guid, &guid, 16));
  125. if (*guid != '-')
  126. return 0;
  127. guid++;
  128. guidcomp = grub_strtoull (guid, 0, 16);
  129. for (i = 0; i < 8; i++)
  130. efivar->guid.data4[i] = (guidcomp >> (56 - 8 * i)) & 0xff;
  131. efivar->attributes = grub_strtoull (attr, 0, 16);
  132. varname = grub_malloc (grub_strlen (name) + 1);
  133. if (! varname)
  134. return 1;
  135. if (unescape (name, varname, varname + grub_strlen (name) + 1, &len))
  136. return 1;
  137. len = grub_utf8_to_utf16 ((grub_uint16_t *) c->nvramptr,
  138. (nvramsize - (c->nvramptr - c->nvram)) / 2,
  139. (grub_uint8_t *) varname, len, NULL);
  140. if (len < 0)
  141. {
  142. grub_error (GRUB_ERR_BAD_ARGUMENT, "broken UTF-8 in variable name");
  143. return 1;
  144. }
  145. c->nvramptr += 2 * len;
  146. *((grub_uint16_t *) c->nvramptr) = 0;
  147. c->nvramptr += 2;
  148. efivar->namelen = 2 * len + 2;
  149. if (unescape (var->value, c->nvramptr, c->nvram + nvramsize, &len))
  150. {
  151. efivar->namelen = 0;
  152. return 1;
  153. }
  154. c->nvramptr += len;
  155. efivar->size = len;
  156. return 0;
  157. }
  158. /* Export stuff for efiemu */
  159. static grub_err_t
  160. nvram_set (void * data __attribute__ ((unused)))
  161. {
  162. const char *env;
  163. /* Take definitive pointers */
  164. grub_uint32_t *nvramsize_def
  165. = grub_efiemu_mm_obtain_request (nvramsize_handle);
  166. grub_uint32_t *high_monotonic_count
  167. = grub_efiemu_mm_obtain_request (high_monotonic_count_handle);
  168. grub_int16_t *timezone
  169. = grub_efiemu_mm_obtain_request (timezone_handle);
  170. grub_uint8_t *daylight
  171. = grub_efiemu_mm_obtain_request (daylight_handle);
  172. grub_uint32_t *accuracy
  173. = grub_efiemu_mm_obtain_request (accuracy_handle);
  174. struct nvram_set_closure c;
  175. c.nvram = grub_efiemu_mm_obtain_request (nvram_handle);
  176. /* Copy to definitive loaction */
  177. grub_dprintf ("efiemu", "preparing pnvram\n");
  178. env = grub_env_get ("EfiEmu.pnvram.high_monotonic_count");
  179. *high_monotonic_count = env ? grub_strtoul (env, 0, 0) : 1;
  180. env = grub_env_get ("EfiEmu.pnvram.timezone");
  181. *timezone = env ? grub_strtosl (env, 0, 0) : GRUB_EFI_UNSPECIFIED_TIMEZONE;
  182. env = grub_env_get ("EfiEmu.pnvram.accuracy");
  183. *accuracy = env ? grub_strtoul (env, 0, 0) : 50000000;
  184. env = grub_env_get ("EfiEmu.pnvram.daylight");
  185. *daylight = env ? grub_strtoul (env, 0, 0) : 0;
  186. c.nvramptr = c.nvram;
  187. grub_memset (c.nvram, 0, nvramsize);
  188. grub_env_iterate (iterate_env, &c);
  189. if (grub_errno)
  190. return grub_errno;
  191. *nvramsize_def = nvramsize;
  192. /* Register symbols */
  193. grub_efiemu_register_symbol ("efiemu_variables", nvram_handle, 0);
  194. grub_efiemu_register_symbol ("efiemu_varsize", nvramsize_handle, 0);
  195. grub_efiemu_register_symbol ("efiemu_high_monotonic_count",
  196. high_monotonic_count_handle, 0);
  197. grub_efiemu_register_symbol ("efiemu_time_zone", timezone_handle, 0);
  198. grub_efiemu_register_symbol ("efiemu_time_daylight", daylight_handle, 0);
  199. grub_efiemu_register_symbol ("efiemu_time_accuracy",
  200. accuracy_handle, 0);
  201. return GRUB_ERR_NONE;
  202. }
  203. static void
  204. nvram_unload (void * data __attribute__ ((unused)))
  205. {
  206. grub_efiemu_mm_return_request (nvram_handle);
  207. grub_efiemu_mm_return_request (nvramsize_handle);
  208. grub_efiemu_mm_return_request (high_monotonic_count_handle);
  209. grub_efiemu_mm_return_request (timezone_handle);
  210. grub_efiemu_mm_return_request (accuracy_handle);
  211. grub_efiemu_mm_return_request (daylight_handle);
  212. }
  213. grub_err_t
  214. grub_efiemu_pnvram (void)
  215. {
  216. const char *size;
  217. grub_err_t err;
  218. nvramsize = 0;
  219. size = grub_env_get ("EfiEmu.pnvram.size");
  220. if (size)
  221. nvramsize = grub_strtoul (size, 0, 0);
  222. if (!nvramsize)
  223. nvramsize = 2048;
  224. err = grub_efiemu_register_prepare_hook (nvram_set, nvram_unload, 0);
  225. if (err)
  226. return err;
  227. nvram_handle
  228. = grub_efiemu_request_memalign (1, nvramsize,
  229. GRUB_EFI_RUNTIME_SERVICES_DATA);
  230. nvramsize_handle
  231. = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t),
  232. GRUB_EFI_RUNTIME_SERVICES_DATA);
  233. high_monotonic_count_handle
  234. = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t),
  235. GRUB_EFI_RUNTIME_SERVICES_DATA);
  236. timezone_handle
  237. = grub_efiemu_request_memalign (1, sizeof (grub_uint16_t),
  238. GRUB_EFI_RUNTIME_SERVICES_DATA);
  239. daylight_handle
  240. = grub_efiemu_request_memalign (1, sizeof (grub_uint8_t),
  241. GRUB_EFI_RUNTIME_SERVICES_DATA);
  242. accuracy_handle
  243. = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t),
  244. GRUB_EFI_RUNTIME_SERVICES_DATA);
  245. return GRUB_ERR_NONE;
  246. }