From ed16607e1387d121a21ccf8c7ff77ab3524fee10 Mon Sep 17 00:00:00 2001 From: hollisb Date: Fri, 22 Apr 2005 02:32:37 +0000 Subject: [PATCH] 2005-04-21 Hollis Blanchard * include/grub/powerpc/ieee1275/ieee1275.h (grub_ieee1275_encode_devname): New prototype. (grub_ieee1275_get_filename): Likewise. * kern/powerpc/ieee1275/init.c (grub_translate_ieee175_path): New function. (grub_set_prefix): Likewise. (grub_machine_init): Call grub_set_prefix. * kern/powerpc/ieee1275/openfw.c: Fix typos. (grub_parse_type): New enum. (grub_ieee1275_get_devargs): New function. (grub_ieee1275_get_devname): Likewise. (grub_ieee1275_parse_args): Likewise. (grub_ieee1275_get_filename): Likewise. (grub_ieee1275_encode_devname): Likewise. --- ChangeLog | 17 +++ include/grub/powerpc/ieee1275/ieee1275.h | 2 + kern/powerpc/ieee1275/init.c | 65 ++++++++- kern/powerpc/ieee1275/openfw.c | 160 ++++++++++++++++++++++- 4 files changed, 241 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index ced5e8e2c..485bad963 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2005-04-21 Hollis Blanchard + + * include/grub/powerpc/ieee1275/ieee1275.h + (grub_ieee1275_encode_devname): New prototype. + (grub_ieee1275_get_filename): Likewise. + * kern/powerpc/ieee1275/init.c (grub_translate_ieee175_path): New + function. + (grub_set_prefix): Likewise. + (grub_machine_init): Call grub_set_prefix. + * kern/powerpc/ieee1275/openfw.c: Fix typos. + (grub_parse_type): New enum. + (grub_ieee1275_get_devargs): New function. + (grub_ieee1275_get_devname): Likewise. + (grub_ieee1275_parse_args): Likewise. + (grub_ieee1275_get_filename): Likewise. + (grub_ieee1275_encode_devname): Likewise. + 2005-03-30 Marco Gerards * kern/powerpc/ieee1275/init.c (grub_machine_fini): Don't call diff --git a/include/grub/powerpc/ieee1275/ieee1275.h b/include/grub/powerpc/ieee1275/ieee1275.h index fc9ac3140..ea4b19eb5 100644 --- a/include/grub/powerpc/ieee1275/ieee1275.h +++ b/include/grub/powerpc/ieee1275/ieee1275.h @@ -134,5 +134,7 @@ void EXPORT_FUNC(abort) (void); void EXPORT_FUNC (grub_reboot) (void); void EXPORT_FUNC (grub_halt) (void); +char *EXPORT_FUNC(grub_ieee1275_encode_devname) (const char *path); +char *EXPORT_FUNC(grub_ieee1275_get_filename) (const char *path); #endif /* ! GRUB_IEEE1275_MACHINE_HEADER */ diff --git a/kern/powerpc/ieee1275/init.c b/kern/powerpc/ieee1275/init.c index a5999ea8b..dff312625 100644 --- a/kern/powerpc/ieee1275/init.c +++ b/kern/powerpc/ieee1275/init.c @@ -46,6 +46,69 @@ abort (void) for (;;); } +/* Translate an OF filesystem path (separated by backslashes), into a GRUB + path (separated by forward slashes). */ +static void +grub_translate_ieee1275_path (char *filepath) +{ + char *backslash; + + backslash = grub_strchr (filepath, '\\'); + while (backslash != 0) + { + *backslash = '/'; + backslash = grub_strchr (filepath, '\\'); + } +} + +static void +grub_set_prefix (void) +{ + char bootpath[64]; /* XXX check length */ + char *filename; + char *prefix; + grub_ieee1275_phandle_t chosen; + + grub_ieee1275_finddevice ("/chosen", &chosen); + if (grub_ieee1275_get_property (chosen, "bootpath", &bootpath, + sizeof (bootpath), 0)) + { + /* Should never happen. */ + grub_printf ("/chosen/bootpath property missing!\n"); + grub_env_set ("prefix", ""); + return; + } + + /* Transform an OF device path to a GRUB path. */ + + prefix = grub_ieee1275_encode_devname (bootpath); + + filename = grub_ieee1275_get_filename (bootpath); + if (filename) + { + char *newprefix; + char *lastslash = grub_strrchr (filename, '\\'); + + /* Truncate at last directory. */ + if (lastslash) + { + *lastslash = '\0'; + grub_translate_ieee1275_path (filename); + + newprefix = grub_malloc (grub_strlen (prefix) + + grub_strlen (filename)); + grub_sprintf (newprefix, "%s%s", prefix, filename); + grub_free (prefix); + prefix = newprefix; + } + } + + grub_env_set ("prefix", prefix); + + grub_free (filename); + grub_free (prefix); +} + void grub_machine_init (void) { @@ -65,7 +128,7 @@ grub_machine_init (void) } grub_mm_init_region ((void *) grub_heap_start, grub_heap_len); - grub_env_set ("prefix", ""); + grub_set_prefix (); grub_ofdisk_init (); } diff --git a/kern/powerpc/ieee1275/openfw.c b/kern/powerpc/ieee1275/openfw.c index b1406f3ce..9d1654c2f 100644 --- a/kern/powerpc/ieee1275/openfw.c +++ b/kern/powerpc/ieee1275/openfw.c @@ -23,6 +23,12 @@ #include #include +enum grub_ieee1275_parse_type +{ + GRUB_PARSE_FILENAME, + GRUB_PARSE_PARTITION, +}; + /* Walk children of 'devpath', calling hook for each. */ grub_err_t grub_children_iterate (char *devpath, @@ -64,7 +70,7 @@ grub_children_iterate (char *devpath, if (actual == -1) continue; - grub_sprintf(fullname, "%s/%s", devpath, childname); + grub_sprintf (fullname, "%s/%s", devpath, childname); alias.type = childtype; alias.path = childpath; @@ -76,7 +82,7 @@ grub_children_iterate (char *devpath, return 0; } -/* Iterate through all device aliasses. Thisfunction can be used to +/* Iterate through all device aliases. This function can be used to find a device of a specific type. */ grub_err_t grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias)) @@ -200,6 +206,156 @@ grub_claimmap (grub_addr_t addr, grub_size_t size) return 0; } +/* Get the device arguments of the Open Firmware node name `path'. */ +static char * +grub_ieee1275_get_devargs (const char *path) +{ + char *colon = grub_strchr (path, ':'); + + if (! colon) + return 0; + + return grub_strdup (colon + 1); +} + +/* Get the device path of the Open Firmware node name `path'. */ +static char * +grub_ieee1275_get_devname (const char *path) +{ + char *colon = grub_strchr (path, ':'); + char *newpath = 0; + int pathlen = grub_strlen (path); + auto int match_alias (struct grub_ieee1275_devalias *alias); + + int match_alias (struct grub_ieee1275_devalias *curalias) + { + /* briQ firmware can change capitalization in /chosen/bootpath. */ + if (! grub_strncasecmp (curalias->path, path, pathlen)) + { + newpath = grub_strndup (curalias->name, grub_strlen (curalias->name)); + return 1; + } + + return 0; + } + + if (colon) + pathlen = (int)(colon - path); + + /* Try to find an alias for this device. */ + grub_devalias_iterate (match_alias); + + if (! newpath) + newpath = grub_strdup (path); + + return newpath; +} + +static char * +grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype) +{ + char type[64]; /* XXX check size. */ + char *device = grub_ieee1275_get_devname (path); + char *args = grub_ieee1275_get_devargs (path); + char *ret = 0; + grub_ieee1275_phandle_t dev; + + if (!args) + /* Shouldn't happen. */ + return 0; + + /* We need to know what type of device it is in order to parse the full + file path properly. */ + if (grub_ieee1275_finddevice (device, &dev)) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Device %s not found\n", device); + goto fail; + } + if (grub_ieee1275_get_property (dev, "device_type", &type, sizeof type, 0)) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "Device %s lacks a device_type property\n", device); + goto fail; + } + + if (!grub_strcmp ("block", type)) + { + /* The syntax of the device arguments is defined in the CHRP and PReP + IEEE1275 bindings: "[partition][,[filename]]". */ + char *comma = grub_strchr (args, ','); + + if (ptype == GRUB_PARSE_FILENAME) + { + if (comma) + { + char *filepath = comma + 1; + + ret = grub_malloc (grub_strlen (filepath) + 1); + /* Make sure filepath has leading backslash. */ + if (filepath[0] != '\\') + grub_sprintf (ret, "\\%s", filepath); + else + grub_strcpy (ret, filepath); + } + } + else if (ptype == GRUB_PARSE_PARTITION) + { + if (!comma) + ret = grub_strdup (args); + else + ret = grub_strndup (args, (grub_size_t)(comma - args)); + } + } + else + { + /* XXX Handle net devices by configuring & registering a grub_net_dev + here, then return its name? + Example path: "net:,,,,,". */ + grub_printf ("Unsupported type %s for device %s\n", type, device); + } + +fail: + grub_free (device); + grub_free (args); + return ret; +} + +char * +grub_ieee1275_get_filename (const char *path) +{ + return grub_ieee1275_parse_args (path, GRUB_PARSE_FILENAME); +} + +/* Convert a device name from IEEE1275 syntax to GRUB syntax. */ +char * +grub_ieee1275_encode_devname (const char *path) +{ + char *device = grub_ieee1275_get_devname (path); + char *partition = grub_ieee1275_parse_args (path, GRUB_PARSE_PARTITION); + char *encoding; + + if (partition) + { + unsigned int partno = grub_strtoul (partition, 0, 0); + partno--; /* GRUB partition numbering is 0-based. */ + + /* Assume partno will require less than five bytes to encode. */ + encoding = grub_malloc (grub_strlen (device) + 3 + 5); + grub_sprintf (encoding, "(%s,%d)", device, partno); + } + else + { + encoding = grub_malloc (grub_strlen (device) + 2); + grub_sprintf (encoding, "(%s)", device); + } + + grub_free (partition); + grub_free (device); + + return encoding; +} + void grub_reboot (void) {