diff --git a/ChangeLog b/ChangeLog
index aa2b0f5..50c48e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
2009-08-24 Vladimir Serbinenko
+ Eliminate ad-hoc tree format in XNU and EfiEmu.
+
+ * efiemu/main.c (grub_efiemu_prepare): Update comment.
+ * efiemu/pnvram.c: Rewritten to use environment variables.
+ All users updated.
+ * include/grub/xnu.h (grub_xnu_fill_devicetree): New prototype.
+ * loader/i386/xnu.c (grub_xnu_boot): Call grub_cpu_xnu_fill_devicetree
+ and grub_xnu_fill_devicetree.
+ * loader/xnu.c (grub_cmd_xnu_kernel): Don't call
+ grub_cpu_xnu_fill_devicetree.
+ (grub_xnu_parse_devtree): Removed.
+ (grub_cmd_xnu_devtree): Likewise.
+ (hextoval): New function.
+ (unescape): Likewise.
+ (grub_xnu_fill_devicetree): Likewise.
+
+2009-08-24 Vladimir Serbinenko
+
UTF-8 to UTF-16 transformation.
* conf/common.rmk (pkglib_MODULES): Add utf.mod
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..8e2c4aa 100644
--- a/efiemu/pnvram.c
+++ b/efiemu/pnvram.c
@@ -18,6 +18,7 @@
*/
#include
+#include
#include
#include
#include
@@ -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 = 0;
+
+ 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++;
-
- /* Attributes can be just parsed by existing functions */
- efivar->attributes = grub_strtoul (ptr, &ptr, 16);
-
- 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;
- /* 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;
-}
+ nvramsize = 0;
-static grub_err_t
-grub_efiemu_make_nvram (void)
-{
- grub_err_t err;
+ size = grub_env_get ("EfiEmu.pnvram.size");
+ if (size)
+ nvramsize = grub_strtoul (size, 0, 0);
- 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/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/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..87574fd 100644
--- a/loader/xnu.c
+++ b/loader/xnu.c
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
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 .
-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"