-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
diff --git a/conf/common.rmk b/conf/common.rmk
index b0d3785..b5a6048 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -617,3 +617,8 @@ pkglib_MODULES += setjmp.mod
 setjmp_mod_SOURCES = lib/$(target_cpu)/setjmp.S
 setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS)
 setjmp_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+pkglib_MODULES += utf.mod
+utf_mod_SOURCES = lib/utf.c
+utf_mod_CFLAGS = $(COMMON_CFLAGS)
+utf_mod_LDFLAGS = $(COMMON_LDFLAGS)
diff --git a/efiemu/main.c b/efiemu/main.c
index b5608e6..25d449c 100644
--- a/efiemu/main.c
+++ b/efiemu/main.c
@@ -282,7 +282,7 @@ grub_efiemu_prepare (void)
 
   err = grub_efiemu_autocore ();
 
-  /* Create NVRAM if not yet done. */
+  /* Create NVRAM. */
   grub_efiemu_pnvram ();
 
   if (grub_efiemu_sizeof_uintn_t () == 4)
@@ -316,9 +316,6 @@ grub_cmd_efiemu_load (grub_command_t cmd __attribute__ 
((unused)),
 
 static grub_command_t cmd_loadcore, cmd_prepare, cmd_unload;
 
-void
-grub_efiemu_pnvram_cmd_register (void);
-
 GRUB_MOD_INIT(efiemu)
 {
   cmd_loadcore = grub_register_command ("efiemu_loadcore",
@@ -332,7 +329,6 @@ GRUB_MOD_INIT(efiemu)
   cmd_unload = grub_register_command ("efiemu_unload", grub_cmd_efiemu_unload,
                                      "efiemu_unload",
                                      "Unload  EFI emulator");
-  grub_efiemu_pnvram_cmd_register ();
 }
 
 GRUB_MOD_FINI(efiemu)
@@ -340,5 +336,4 @@ GRUB_MOD_FINI(efiemu)
   grub_unregister_command (cmd_loadcore);
   grub_unregister_command (cmd_prepare);
   grub_unregister_command (cmd_unload);
-  grub_efiemu_pnvram_cmd_unregister ();
 }
diff --git a/efiemu/pnvram.c b/efiemu/pnvram.c
index 04ad6e2..c0b19bb 100644
--- a/efiemu/pnvram.c
+++ b/efiemu/pnvram.c
@@ -18,6 +18,7 @@
  */
 
 #include <grub/file.h>
+#include <grub/utf.h>
 #include <grub/err.h>
 #include <grub/normal.h>
 #include <grub/mm.h>
@@ -34,62 +35,181 @@ static int timezone_handle = 0;
 static int accuracy_handle = 0;
 static int daylight_handle = 0;
 
-/* Temporary place */
-static grub_uint8_t *nvram;
 static grub_size_t nvramsize;
-static grub_uint32_t high_monotonic_count;
-static grub_int16_t timezone;
-static grub_uint8_t daylight;
-static grub_uint32_t accuracy;
-
-static const struct grub_arg_option options[] = {
-  {"size", 's', 0, "number of bytes to reserve for pseudo NVRAM", 0,
-   ARG_TYPE_INT},
-  {"high-monotonic-count", 'm', 0,
-   "Initial value of high monotonic count", 0, ARG_TYPE_INT},
-  {"timezone", 't', 0,
-   "Timezone, offset in minutes from GMT", 0, ARG_TYPE_INT},
-  {"accuracy", 'a', 0,
-   "Accuracy of clock, in 1e-12 units", 0, ARG_TYPE_INT},
-  {"daylight", 'd', 0,
-   "Daylight value, as per EFI specifications", 0, ARG_TYPE_INT},
-  {0, 0, 0, 0, 0, 0}
-};
 
 /* Parse signed value */
 static int
-grub_strtosl (char *arg, char **end, int base)
+grub_strtosl (const char *arg, char **end, int base)
 {
   if (arg[0] == '-')
     return -grub_strtoul (arg + 1, end, base);
   return grub_strtoul (arg, end, base);
 }
 
+static inline int
+hextoval (char c)
+{
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  if (c >= 'a' && c <= 'z')
+    return c - 'a' + 10;
+  if (c >= 'A' && c <= 'Z')
+    return c - 'A' + 10;
+  return 0;
+}
+
+static inline grub_err_t
+unescape (char *in, char *out, char *outmax, int *len)
+{
+  char *ptr, *dptr;
+  dptr = out;
+  for (ptr = in; *ptr && dptr < outmax; )
+    if (*ptr == '%' && ptr[1] && ptr[2])
+      {
+       *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2]));
+       ptr += 3;
+       dptr++;
+      }
+    else
+      {
+       *dptr = *ptr;
+       ptr++;
+       dptr++;
+      }
+  if (dptr == outmax)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                      "Too many NVRAM variables for reserved variable space."
+                      " Try increasing EfiEmu.pnvram.size.");
+  *len = dptr - out;
+  return 0;
+}
+
 /* Export stuff for efiemu */
 static grub_err_t
 nvram_set (void * data __attribute__ ((unused)))
 {
+  const char *env;
   /* Take definitive pointers */
-  grub_uint8_t *nvram_def = grub_efiemu_mm_obtain_request (nvram_handle);
+  char *nvram = grub_efiemu_mm_obtain_request (nvram_handle);
   grub_uint32_t *nvramsize_def
     = grub_efiemu_mm_obtain_request (nvramsize_handle);
-  grub_uint32_t *high_monotonic_count_def
+  grub_uint32_t *high_monotonic_count
     = grub_efiemu_mm_obtain_request (high_monotonic_count_handle);
-  grub_int16_t *timezone_def
+  grub_int16_t *timezone
     = grub_efiemu_mm_obtain_request (timezone_handle);
-  grub_uint8_t *daylight_def
+  grub_uint8_t *daylight
     = grub_efiemu_mm_obtain_request (daylight_handle);
-  grub_uint32_t *accuracy_def
+  grub_uint32_t *accuracy
     = grub_efiemu_mm_obtain_request (accuracy_handle);
+  char *nvramptr;
+
+  auto int iterate_env (struct grub_env_var *var);
+  int iterate_env (struct grub_env_var *var)
+  {
+    char *guid, *attr, *name, *varname;
+    struct efi_variable *efivar;
+    int len;
+       
+    if (grub_memcmp (var->name, "EfiEmu.pnvram.",
+                    sizeof ("EfiEmu.pnvram.") - 1) != 0)
+      return 0;
+
+    guid = var->name + sizeof ("EfiEmu.pnvram.") - 1;
+
+    attr = grub_strchr (guid, '.');
+    if (!attr)
+      return 0;
+    attr++;
+
+    name = grub_strchr (attr, '.');
+    if (!name)
+      return 0;
+    name++;
+
+    efivar = (struct efi_variable *) nvramptr;
+    if (nvramptr - nvram + sizeof (struct efi_variable) > nvramsize)
+      {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                   "Too many NVRAM variables for reserved variable space."
+                   " Try increasing EfiEmu.pnvram.size.");
+       return 1;
+      }
+
+    nvramptr += sizeof (struct efi_variable);
+
+    efivar->guid.data1 = grub_cpu_to_le32 (grub_strtoul (guid, &guid, 16));
+    if (*guid != '-')
+      return 0;
+    guid++;
+
+    efivar->guid.data2 = grub_cpu_to_le16 (grub_strtoul (guid, &guid, 16));
+    if (*guid != '-')
+      return 0;
+    guid++;
+
+    efivar->guid.data3 = grub_cpu_to_le16 (grub_strtoul (guid, &guid, 16));
+    if (*guid != '-')
+      return 0;
+    guid++;
+
+    *(grub_uint64_t *) &(efivar->guid.data4)
+      = grub_cpu_to_be64 (grub_strtoull (guid, 0, 16));
+
+    efivar->attributes = grub_strtoull (attr, 0, 16);
+
+    varname = grub_malloc (grub_strlen (name) + 1);
+    if (! varname)
+      return 1;
+
+    if (unescape (name, varname, varname + grub_strlen (name) + 1, &len))
+      return 1;
+
+    len = grub_utf8_to_utf16 ((grub_uint16_t *) nvramptr,
+                             (nvramsize - (nvramptr - nvram)) / 2,
+                             (grub_uint8_t *) varname, len, NULL);
+
+    if (len < 0)
+      {
+       grub_error (GRUB_ERR_BAD_ARGUMENT, "Broken UTF-8 in variable name\n");
+       return 1;
+      }
+
+    nvramptr += 2 * len;
+    *((grub_uint16_t *) nvramptr) = 0;
+    nvramptr += 2;
+    efivar->namelen = 2 * len + 2;
+
+    if (unescape (var->value, nvramptr, nvram + nvramsize, &len))
+      {
+       efivar->namelen = 0;
+       return 1;
+      }
+
+    nvramptr += len;
+
+    efivar->size = len;
+
+    return 0;
+  }
 
   /* Copy to definitive loaction */
   grub_dprintf ("efiemu", "preparing pnvram\n");
-  grub_memcpy (nvram_def, nvram, nvramsize);
+
+  env = grub_env_get ("EfiEmu.pnvram.high_monotonic_count");
+  *high_monotonic_count = env ? grub_strtoul (env, 0, 0) : 1;
+  env = grub_env_get ("EfiEmu.pnvram.timezone");
+  *timezone = env ? grub_strtosl (env, 0, 0) : GRUB_EFI_UNSPECIFIED_TIMEZONE;
+  env = grub_env_get ("EfiEmu.pnvram.accuracy");
+  *accuracy = env ? grub_strtoul (env, 0, 0) : 50000000;
+  env = grub_env_get ("EfiEmu.pnvram.daylight");
+  *daylight = env ? grub_strtoul (env, 0, 0) : 0;
+
+  nvramptr = nvram;
+  grub_memset (nvram, 0, nvramsize);
+  grub_env_iterate (iterate_env);
+  if (grub_errno)
+    return grub_errno;
   *nvramsize_def = nvramsize;
-  *high_monotonic_count_def = high_monotonic_count;
-  *timezone_def = timezone;
-  *daylight_def = daylight;
-  *accuracy_def = accuracy;
 
   /* Register symbols */
   grub_efiemu_register_symbol ("efiemu_variables", nvram_handle, 0);
@@ -113,197 +233,27 @@ nvram_unload (void * data __attribute__ ((unused)))
   grub_efiemu_mm_return_request (timezone_handle);
   grub_efiemu_mm_return_request (accuracy_handle);
   grub_efiemu_mm_return_request (daylight_handle);
-
-  grub_free (nvram);
-  nvram = 0;
 }
 
-/* Load the variables file It's in format
-   guid1:attr1:name1:data1;
-   guid2:attr2:name2:data2;
-   ...
-   Where all fields are in hex
-*/
-static grub_err_t
-read_pnvram (char *filename)
+grub_err_t
+grub_efiemu_pnvram (void)
 {
-  char *buf, *ptr, *ptr2;
-  grub_file_t file;
-  grub_size_t size;
-  grub_uint8_t *nvramptr = nvram;
-  struct efi_variable *efivar;
-  grub_size_t guidlen, datalen;
-  unsigned i, j;
-
-  file = grub_file_open (filename);
-  if (!file)
-    return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram");
-  size = grub_file_size (file);
-  buf = grub_malloc (size + 1);
-  if (!buf)
-    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read pnvram");
-  if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
-    return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram");
-  buf[size] = 0;
-  grub_file_close (file);
-
-  for (ptr = buf; *ptr; )
-    {
-      if (grub_isspace (*ptr))
-       {
-         ptr++;
-         continue;
-       }
-
-      efivar = (struct efi_variable *) nvramptr;
-      if (nvramptr - nvram + sizeof (struct efi_variable) > nvramsize)
-       return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                          "file is too large for reserved variable space");
-
-      nvramptr += sizeof (struct efi_variable);
-
-      /* look ahow long guid field is*/
-      guidlen = 0;
-      for (ptr2 = ptr; (grub_isspace (*ptr2)
-                       || (*ptr2 >= '0' && *ptr2 <= '9')
-                       || (*ptr2 >= 'a' && *ptr2 <= 'f')
-                       || (*ptr2 >= 'A' && *ptr2 <= 'F'));
-          ptr2++)
-       if (!grub_isspace (*ptr2))
-         guidlen++;
-      guidlen /= 2;
-
-      /* Read guid */
-      if (guidlen != sizeof (efivar->guid))
-       {
-         grub_free (buf);
-         return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
-       }
-      for (i = 0; i < 2 * sizeof (efivar->guid); i++)
-       {
-         int hex = 0;
-         while (grub_isspace (*ptr))
-           ptr++;
-         if (*ptr >= '0' && *ptr <= '9')
-           hex = *ptr - '0';
-         if (*ptr >= 'a' && *ptr <= 'f')
-           hex = *ptr - 'a' + 10;
-         if (*ptr >= 'A' && *ptr <= 'F')
-           hex = *ptr - 'A' + 10;
-
-         if (i%2 == 0)
-           ((grub_uint8_t *)&(efivar->guid))[i/2] = hex << 4;
-         else
-           ((grub_uint8_t *)&(efivar->guid))[i/2] |= hex;
-         ptr++;
-       }
-
-      while (grub_isspace (*ptr))
-       ptr++;
-      if (*ptr != ':')
-       {
-         grub_dprintf ("efiemu", "Not colon\n");
-         grub_free (buf);
-         return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
-       }
-      ptr++;
-      while (grub_isspace (*ptr))
-       ptr++;
+  const char *size;
+  grub_err_t err;
 
-      /* Attributes can be just parsed by existing functions */
-      efivar->attributes = grub_strtoul (ptr, &ptr, 16);
+  nvramsize = 0;
 
-      while (grub_isspace (*ptr))
-       ptr++;
-      if (*ptr != ':')
-       {
-         grub_dprintf ("efiemu", "Not colon\n");
-         grub_free (buf);
-         return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
-       }
-      ptr++;
-      while (grub_isspace (*ptr))
-       ptr++;
+  size = grub_env_get ("EfiEmu.pnvram.size");
+  if (size)
+    nvramsize = grub_strtoul (size, 0, 0);
 
-      /* Read name and value */
-      for (j = 0; j < 2; j++)
-       {
-         /* Look the length */
-         datalen = 0;
-         for (ptr2 = ptr; *ptr2 && (grub_isspace (*ptr2)
-                                    || (*ptr2 >= '0' && *ptr2 <= '9')
-                                    || (*ptr2 >= 'a' && *ptr2 <= 'f')
-                                    || (*ptr2 >= 'A' && *ptr2 <= 'F'));
-              ptr2++)
-           if (!grub_isspace (*ptr2))
-             datalen++;
-         datalen /= 2;
-
-         if (nvramptr - nvram + datalen > nvramsize)
-           {
-             grub_free (buf);
-             return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                                "file is too large for reserved "
-                                " variable space");
-           }
-
-         for (i = 0; i < 2 * datalen; i++)
-           {
-             int hex = 0;
-             while (grub_isspace (*ptr))
-               ptr++;
-             if (*ptr >= '0' && *ptr <= '9')
-               hex = *ptr - '0';
-             if (*ptr >= 'a' && *ptr <= 'f')
-               hex = *ptr - 'a' + 10;
-             if (*ptr >= 'A' && *ptr <= 'F')
-               hex = *ptr - 'A' + 10;
-
-             if (i%2 == 0)
-               nvramptr[i/2] = hex << 4;
-             else
-               nvramptr[i/2] |= hex;
-             ptr++;
-           }
-         nvramptr += datalen;
-         while (grub_isspace (*ptr))
-           ptr++;
-         if (*ptr != (j ? ';' : ':'))
-           {
-             grub_free (buf);
-             grub_dprintf ("efiemu", j?"Not semicolon\n":"Not colon\n");
-             return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
-           }
-         if (j)
-           efivar->size = datalen;
-         else
-           efivar->namelen = datalen;
-
-         ptr++;
-       }
-    }
-  grub_free (buf);
-  return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_efiemu_make_nvram (void)
-{
-  grub_err_t err;
-
-  err = grub_efiemu_autocore ();
-  if (err)
-    {
-      grub_free (nvram);
-      return err;
-    }
+  if (!nvramsize)
+    nvramsize = 2048;
 
   err = grub_efiemu_register_prepare_hook (nvram_set, nvram_unload, 0);
   if (err)
-    {
-      grub_free (nvram);
-      return err;
-    }
+    return err;
+
   nvram_handle
     = grub_efiemu_request_memalign (1, nvramsize,
                                    GRUB_EFI_RUNTIME_SERVICES_DATA);
@@ -326,75 +276,3 @@ grub_efiemu_make_nvram (void)
   grub_efiemu_request_symbols (6);
   return GRUB_ERR_NONE;
 }
-
-grub_err_t
-grub_efiemu_pnvram (void)
-{
-  if (nvram)
-    return GRUB_ERR_NONE;
-
-  nvramsize = 2048;
-  high_monotonic_count = 1;
-  timezone = GRUB_EFI_UNSPECIFIED_TIMEZONE;
-  accuracy = 50000000;
-  daylight = 0;
-
-  nvram = grub_zalloc (nvramsize);
-  if (!nvram)
-    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                      "Couldn't allocate space for temporary pnvram storage");
-
-  return grub_efiemu_make_nvram ();
-}
-
-static grub_err_t
-grub_cmd_efiemu_pnvram (struct grub_extcmd *cmd,
-                       int argc, char **args)
-{
-  struct grub_arg_list *state = cmd->state;
-  grub_err_t err;
-
-  if (argc > 1)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one argument expected");
-
-  nvramsize = state[0].set ? grub_strtoul (state[0].arg, 0, 0) : 2048;
-  high_monotonic_count = state[1].set ? grub_strtoul (state[1].arg, 0, 0) : 1;
-  timezone = state[2].set ? grub_strtosl (state[2].arg, 0, 0)
-    : GRUB_EFI_UNSPECIFIED_TIMEZONE;
-  accuracy = state[3].set ? grub_strtoul (state[3].arg, 0, 0) : 50000000;
-  daylight = state[4].set ? grub_strtoul (state[4].arg, 0, 0) : 0;
-
-  nvram = grub_zalloc (nvramsize);
-  if (!nvram)
-    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                      "Couldn't allocate space for temporary pnvram storage");
-
-  if (argc == 1 && (err = read_pnvram (args[0])))
-    {
-      grub_free (nvram);
-      return err;
-    }
-  return grub_efiemu_make_nvram ();
-}
-
-static grub_extcmd_t cmd;
-
-void grub_efiemu_pnvram_cmd_register (void);
-void grub_efiemu_pnvram_cmd_unregister (void);
-
-void
-grub_efiemu_pnvram_cmd_register (void)
-{
-  cmd = grub_register_extcmd ("efiemu_pnvram", grub_cmd_efiemu_pnvram,
-                             GRUB_COMMAND_FLAG_BOTH,
-                             "efiemu_pnvram [FILENAME]",
-                             "Initialise pseudo-NVRAM and load variables "
-                             "from FILE",
-                             options);
-}
-
-void
-grub_efiemu_pnvram_cmd_unregister (void)
-{
-  grub_unregister_extcmd (cmd);
-}
diff --git a/include/grub/utf.h b/include/grub/utf.h
new file mode 100644
index 0000000..2091916
--- /dev/null
+++ b/include/grub/utf.h
@@ -0,0 +1,29 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_UTF_HEADER
+#define GRUB_UTF_HEADER        1
+
+#include <grub/types.h>
+
+grub_ssize_t
+grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
+                   const grub_uint8_t *src, grub_size_t srcsize,
+                   const grub_uint8_t **srcend);
+
+#endif
diff --git a/include/grub/xnu.h b/include/grub/xnu.h
index c3902e6..2abafac 100644
--- a/include/grub/xnu.h
+++ b/include/grub/xnu.h
@@ -100,6 +100,7 @@ grub_err_t grub_xnu_scan_dir_for_kexts (char *dirname, char 
*osbundlerequired,
 grub_err_t grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired,
                                        int maxrecursion);
 void *grub_xnu_heap_malloc (int size);
+grub_err_t grub_xnu_fill_devicetree (void);
 extern grub_uint32_t grub_xnu_heap_real_start;
 extern grub_size_t grub_xnu_heap_size;
 extern char *grub_xnu_heap_start;
diff --git a/lib/utf.c b/lib/utf.c
new file mode 100644
index 0000000..1f89f2f
--- /dev/null
+++ b/lib/utf.c
@@ -0,0 +1,116 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009  Free 
Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
+   bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string.
+   Return the number of characters converted. DEST must be able to hold
+   at least DESTSIZE characters. If an invalid sequence is found, return -1.
+   If SRCEND is not NULL, then *SRCEND is set to the next byte after the
+   last byte used in SRC.  */
+
+#include <grub/utf.h>
+
+grub_ssize_t
+grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
+                   const grub_uint8_t *src, grub_size_t srcsize,
+                   const grub_uint8_t **srcend)
+{
+  grub_uint16_t *p = dest;
+  int count = 0;
+  grub_uint32_t code = 0;
+
+  if (srcend)
+    *srcend = src;
+
+  while (srcsize && destsize)
+    {
+      grub_uint32_t c = *src++;
+      if (srcsize != (grub_size_t)-1)
+       srcsize--;
+      if (count)
+       {
+         if ((c & 0xc0) != 0x80)
+           {
+             /* invalid */
+             return -1;
+           }
+         else
+           {
+             code <<= 6;
+             code |= (c & 0x3f);
+             count--;
+           }
+       }
+      else
+       {
+         if (c == 0)
+           break;
+
+         if ((c & 0x80) == 0x00)
+           code = c;
+         else if ((c & 0xe0) == 0xc0)
+           {
+             count = 1;
+             code = c & 0x1f;
+           }
+         else if ((c & 0xf0) == 0xe0)
+           {
+             count = 2;
+             code = c & 0x0f;
+           }
+         else if ((c & 0xf8) == 0xf0)
+           {
+             count = 3;
+             code = c & 0x07;
+           }
+         else if ((c & 0xfc) == 0xf8)
+           {
+             count = 4;
+             code = c & 0x03;
+           }
+         else if ((c & 0xfe) == 0xfc)
+           {
+             count = 5;
+             code = c & 0x01;
+           }
+         else
+           return -1;
+       }
+
+      if (count == 0)
+       {
+         if (destsize < 2 && code > 0x10000)
+           break;
+         if (code > 0x10000)
+           {
+             *p++ = 0xD800 + (((code - 0x10000) >> 12) & 0xfff);
+             *p++ = 0xDC00 + ((code - 0x10000) & 0xfff);
+             destsize -= 2;
+           }
+         else
+           {
+             *p++ = code;
+             destsize--;
+           }
+       }
+    }
+
+  if (srcend)
+    *srcend = src;
+  return p - dest;
+}
diff --git a/loader/i386/xnu.c b/loader/i386/xnu.c
index 06e375c..686634b 100644
--- a/loader/i386/xnu.c
+++ b/loader/i386/xnu.c
@@ -439,6 +439,14 @@ grub_xnu_boot (void)
   grub_size_t devtreelen;
   int i;
 
+  err = grub_cpu_xnu_fill_devicetree ();
+  if (err)
+    return err;
+
+  err = grub_xnu_fill_devicetree ();
+  if (err)
+    return err;
+
   /* Page-align to avoid following parts to be inadvertently freed. */
   err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
   if (err)
diff --git a/loader/xnu.c b/loader/xnu.c
index aac4ae3..156e0e3 100644
--- a/loader/xnu.c
+++ b/loader/xnu.c
@@ -31,6 +31,7 @@
 #include <grub/gzio.h>
 #include <grub/command.h>
 #include <grub/misc.h>
+#include <grub/env.h>
 
 struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0;
 static int driverspackagenum = 0;
@@ -436,10 +437,6 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ 
((unused)),
   if (ptr != grub_xnu_cmdline)
     *(ptr - 1) = 0;
 
-  err = grub_cpu_xnu_fill_devicetree ();
-  if (err)
-    return err;
-
   grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
 
   grub_xnu_lock ();
@@ -739,135 +736,6 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ 
((unused)),
   return grub_xnu_register_memory ("RAMDisk", 0, loadto, size);
 }
 
-/* Parse a devtree file. It uses the following format:
-   valuename:valuedata;
-   keyname{
-     contents
-   }
-   keyname, valuename and valuedata are in hex.
- */
-static char *
-grub_xnu_parse_devtree (struct grub_xnu_devtree_key **parent,
-                       char *start, char *end)
-{
-  char *ptr, *ptr2;
-  char *name, *data;
-  int namelen, datalen, i;
-  for (ptr = start; ptr && ptr < end; )
-    {
-      if (grub_isspace (*ptr))
-       {
-         ptr++;
-         continue;
-       }
-      if (*ptr == '}')
-       return ptr + 1;
-      namelen = 0;
-
-      /* Parse the name. */
-      for (ptr2 = ptr; ptr2 < end && (grub_isspace (*ptr2)
-                                     || (*ptr2 >= '0' && *ptr2 <= '9')
-                                     || (*ptr2 >= 'a' && *ptr2 <= 'f')
-                                     || (*ptr2 >= 'A' && *ptr2 <= 'F'));
-          ptr2++)
-       if (! grub_isspace (*ptr2))
-         namelen++;
-      if (ptr2 == end)
-       return 0;
-      namelen /= 2;
-      name = grub_malloc (namelen + 1);
-      if (!name)
-       return 0;
-      for (i = 0; i < 2 * namelen; i++)
-       {
-         int hex = 0;
-         while (grub_isspace (*ptr))
-           ptr++;
-         if (*ptr >= '0' && *ptr <= '9')
-           hex = *ptr - '0';
-         if (*ptr >= 'a' && *ptr <= 'f')
-           hex = *ptr - 'a' + 10;
-         if (*ptr >= 'A' && *ptr <= 'F')
-           hex = *ptr - 'A' + 10;
-
-         if (i % 2 == 0)
-           name[i / 2] = hex << 4;
-         else
-           name[i / 2] |= hex;
-         ptr++;
-       }
-      name [namelen] = 0;
-      while (grub_isspace (*ptr))
-       ptr++;
-
-      /* If it describes a key recursively invoke the function. */
-      if (*ptr == '{')
-       {
-         struct grub_xnu_devtree_key *newkey
-           = grub_xnu_create_key (parent, name);
-         grub_free (name);
-         if (! newkey)
-           return 0;
-         ptr = grub_xnu_parse_devtree (&(newkey->first_child), ptr + 1, end);
-         continue;
-       }
-
-      /* Parse the data. */
-      if (*ptr != ':')
-       return 0;
-      ptr++;
-      datalen = 0;
-      for (ptr2 = ptr; ptr2 < end && (grub_isspace (*ptr2)
-                                     || (*ptr2 >= '0' && *ptr2 <= '9')
-                                     || (*ptr2 >= 'a' && *ptr2 <= 'f')
-                                     || (*ptr2 >= 'A' && *ptr2 <= 'F'));
-          ptr2++)
-       if (! grub_isspace (*ptr2))
-         datalen++;
-      if (ptr2 == end)
-       return 0;
-      datalen /= 2;
-      data = grub_malloc (datalen);
-      if (! data)
-       return 0;
-      for (i = 0; i < 2 * datalen; i++)
-       {
-         int hex = 0;
-         while (grub_isspace (*ptr))
-           ptr++;
-         if (*ptr >= '0' && *ptr <= '9')
-           hex = *ptr - '0';
-         if (*ptr >= 'a' && *ptr <= 'f')
-           hex = *ptr - 'a' + 10;
-         if (*ptr >= 'A' && *ptr <= 'F')
-           hex = *ptr - 'A' + 10;
-
-         if (i % 2 == 0)
-           data[i / 2] = hex << 4;
-         else
-           data[i / 2] |= hex;
-         ptr++;
-       }
-      while (ptr < end && grub_isspace (*ptr))
-       ptr++;
-      {
-       struct grub_xnu_devtree_key *newkey
-         = grub_xnu_create_value (parent, name);
-       grub_free (name);
-       if (! newkey)
-         return 0;
-       newkey->datasize = datalen;
-       newkey->data = data;
-      }
-      if (*ptr != ';')
-       return 0;
-      ptr++;
-    }
-  if (ptr >= end && *parent != grub_xnu_devtree_root)
-    return 0;
-  return ptr;
-}
-
 /* Returns true if the kext should be loaded according to plist
    and osbundlereq. Also fill BINNAME. */
 static int
@@ -1164,53 +1032,6 @@ grub_xnu_load_kext_from_dir (char *dirname, char 
*osbundlerequired,
   return GRUB_ERR_NONE;
 }
 
-/* Load devtree file. */
-static grub_err_t
-grub_cmd_xnu_devtree (grub_command_t cmd __attribute__ ((unused)),
-                     int argc, char *args[])
-{
-  grub_file_t file;
-  char *data, *endret;
-  grub_size_t datalen;
-
-  if (argc != 1)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT, "Filename required");
-
-  if (! grub_xnu_heap_size)
-    return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
-
-  /* Load the file. */
-  file = grub_gzfile_open (args[0], 1);
-  if (! file)
-    return grub_error (GRUB_ERR_FILE_NOT_FOUND, "Couldn't load device tree");
-  datalen = grub_file_size (file);
-  data = grub_malloc (datalen + 1);
-  if (! data)
-    {
-      grub_file_close (file);
-      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                        "Could load device tree into memory");
-    }
-  if (grub_file_read (file, data, datalen) != (grub_ssize_t) datalen)
-    {
-      grub_file_close (file);
-      grub_free (data);
-      grub_error_push ();
-      return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]);
-    }
-  grub_file_close (file);
-  data[datalen] = 0;
-
-  /* Parse the file. */
-  endret = grub_xnu_parse_devtree (&grub_xnu_devtree_root,
-                                  data, data + datalen);
-  grub_free (data);
-
-  if (! endret)
-    return grub_error (GRUB_ERR_BAD_OS, "Couldn't parse devtree");
-
-  return GRUB_ERR_NONE;
-}
 
 static int locked=0;
 static grub_dl_t my_mod;
@@ -1271,6 +1092,107 @@ grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ 
((unused)),
     }
 }
 
+static inline int
+hextoval (char c)
+{
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  if (c >= 'a' && c <= 'z')
+    return c - 'a' + 10;
+  if (c >= 'A' && c <= 'Z')
+    return c - 'A' + 10;
+  return 0;
+}
+
+static inline void
+unescape (char *name, char *curdot, char *nextdot, int *len)
+{
+  char *ptr, *dptr;
+  dptr = name;
+  for (ptr = curdot; ptr < nextdot;)
+    if (ptr + 2 < nextdot && *ptr == '%')
+      {
+       *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2]));
+       ptr += 3;
+       dptr++;
+      }
+    else
+      {
+       *dptr = *ptr;
+       ptr++;
+       dptr++;
+      }
+  *len = dptr - name;
+}
+
+grub_err_t
+grub_xnu_fill_devicetree (void)
+{
+  auto int iterate_env (struct grub_env_var *var);
+  int iterate_env (struct grub_env_var *var)
+  {
+    char *nextdot = 0, *curdot;
+    struct grub_xnu_devtree_key **curkey = &grub_xnu_devtree_root;
+    struct grub_xnu_devtree_key *curvalue;
+    char *name = 0, *data;
+    int len;
+    
+    if (grub_memcmp (var->name, "XNU.DeviceTree.",
+                    sizeof ("XNU.DeviceTree.") - 1) != 0)
+      return 0;
+
+    curdot = var->name + sizeof ("XNU.DeviceTree.") - 1;
+    nextdot = grub_strchr (curdot, '.');
+    if (nextdot)
+      nextdot++;
+    while (nextdot)
+      {
+       name = grub_realloc (name, nextdot - curdot + 1);
+       
+       if (!name)
+         return 1;
+       
+       unescape (name, curdot, nextdot, &len);
+       name[len - 1] = 0;
+       
+       curkey = &(grub_xnu_create_key (curkey, name)->first_child);
+       
+       curdot = nextdot;
+       nextdot = grub_strchr (nextdot, '.');
+       if (nextdot)
+         nextdot++;
+      }
+
+    nextdot = curdot + grub_strlen (curdot) + 1;
+
+    name = grub_realloc (name, nextdot - curdot + 1);
+    
+    if (!name)
+      return 1;
+    
+    unescape (name, curdot, nextdot, &len);
+    name[len] = 0;
+
+    curvalue = grub_xnu_create_value (curkey, name);
+    grub_free (name);
+    
+    data = grub_malloc (grub_strlen (var->value) + 1);
+    if (!data)
+      return 1;
+    
+    unescape (data, var->value, var->value + grub_strlen (var->value),
+             &len);
+    curvalue->datasize = len;
+    curvalue->data = data;
+
+    return 0;
+  }
+
+  grub_env_iterate (iterate_env);
+
+  return grub_errno;
+}
+
 struct grub_video_bitmap *grub_xnu_bitmap = 0;
 
 static grub_err_t
@@ -1317,7 +1239,7 @@ grub_xnu_unlock ()
 }
 
 static grub_command_t cmd_kernel, cmd_mkext, cmd_kext, cmd_kextdir,
-  cmd_ramdisk, cmd_devtree, cmd_resume, cmd_splash;
+  cmd_ramdisk, cmd_resume, cmd_splash;
 
 GRUB_MOD_INIT(xnu)
 {
@@ -1333,8 +1255,6 @@ GRUB_MOD_INIT(xnu)
   cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0,
                                       "Load XNU ramdisk. "
                                       "It will be seen as md0");
-  cmd_devtree = grub_register_command ("xnu_devtree", grub_cmd_xnu_devtree, 0,
-                                      "Load XNU devtree");
   cmd_splash = grub_register_command ("xnu_splash", grub_cmd_xnu_splash, 0,
                                      "Load a splash image for XNU");
 
@@ -1353,7 +1273,6 @@ GRUB_MOD_FINI(xnu)
   grub_unregister_command (cmd_mkext);
   grub_unregister_command (cmd_kext);
   grub_unregister_command (cmd_kextdir);
-  grub_unregister_command (cmd_devtree);
   grub_unregister_command (cmd_ramdisk);
   grub_unregister_command (cmd_kernel);
   grub_unregister_command (cmd_splash);
diff --git a/util/i386/efi/grub-dumpdevtree b/util/i386/efi/grub-dumpdevtree
index bc13e3c..ce46f55 100644
--- a/util/i386/efi/grub-dumpdevtree
+++ b/util/i386/efi/grub-dumpdevtree
@@ -15,11 +15,9 @@
 # You should have received a copy of the GNU General Public License
 # along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
-hexify()
-{
-  echo -n "$@" | od -A n -t x1 - | sed -e 's/ //g' | tr '\n' '\0'
-}
+string=`ioreg -lw0 -p IODeviceTree -n efi -r -x |grep device-properties | sed 
's/.*<//;s/>.*//;'`
+astring=;
+l=0
+while [ "x${string:l:2}" != x ]; do astring="$astring%${string:l:2}"; 
l=$((l+2)); done
 
-echo "`hexify efi`{    `hexify device-properties`:"
-ioreg -lw0 -p IODeviceTree -n efi -r -x |grep device-properties | sed 
's/.*<//;s/>.*//;'
-echo ";}"
+echo "set XNU.DeviceTree.efi.device-properties=$astring"
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to