static int fill_alias (struct grub_ieee1275_devalias *alias) { grub_ssize_t actual; if (grub_ieee1275_get_property (alias->phandle, "device_type", alias->type, IEEE1275_MAX_PROP_LEN, &actual)) alias->type[0] = 0; if (alias->parent_dev == alias->phandle) return 0; if (grub_ieee1275_package_to_path (alias->phandle, alias->path, IEEE1275_MAX_PATH_LEN, &actual)) return 0; if (grub_strcmp (alias->parent_path, alias->path) == 0) return 0; if (grub_ieee1275_get_property (alias->phandle, "name", alias->name, IEEE1275_MAX_PROP_LEN, &actual)) return 0; grub_dprintf ("devalias", "device path=%s\n", alias->path); return 1; }
static int grub_ofdisk_iterate (int (*hook) (const char *name), grub_disk_pull_t pull) { unsigned i; if (pull != GRUB_DISK_PULL_NONE) return 0; scan (); for (i = 0; i < ARRAY_SIZE (ofdisk_hash); i++) { static struct ofdisk_hash_ent *ent; for (ent = ofdisk_hash[i]; ent; ent = ent->next) { if (!ent->shortest) continue; if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY)) { grub_ieee1275_phandle_t dev; char tmp[8]; if (grub_ieee1275_finddevice (ent->devpath, &dev)) { grub_dprintf ("disk", "finddevice (%s) failed\n", ent->devpath); continue; } if (grub_ieee1275_get_property (dev, "iconname", tmp, sizeof tmp, 0)) { grub_dprintf ("disk", "get iconname failed\n"); continue; } if (grub_strcmp (tmp, "sdmmc") != 0) { grub_dprintf ("disk", "device is not an SD card\n"); continue; } } if (grub_strncmp (ent->shortest, "cdrom", 5) == 0) continue; { char buffer[sizeof ("ieee1275/") + grub_strlen (ent->shortest)]; char *ptr; ptr = grub_stpcpy (buffer, "ieee1275/"); grub_strcpy (ptr, ent->shortest); if (hook (buffer)) return 1; } } } return 0; }
void grub_machine_set_prefix (void) { #ifndef __i386__ char bootpath[64]; /* XXX check length */ char *filename; char *prefix; #endif if (grub_prefix[0]) { grub_env_set ("prefix", grub_prefix); /* Prefix is hardcoded in the core image. */ return; } #ifdef __i386__ grub_env_set ("prefix", "(sd,1)/"); #else if (grub_ieee1275_get_property (grub_ieee1275_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_xasprintf ("%s%s", prefix, filename); if (newprefix) { grub_free (prefix); prefix = newprefix; } } } grub_env_set ("prefix", prefix); grub_free (filename); grub_free (prefix); #endif }
/* Walk children of 'devpath', calling hook for each. */ grub_err_t grub_children_iterate (char *devpath, int (*hook) (struct grub_ieee1275_devalias *alias)) { grub_ieee1275_phandle_t dev; grub_ieee1275_phandle_t child; if (grub_ieee1275_finddevice (devpath, &dev)) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Unknown device"); if (grub_ieee1275_child (dev, &child)) return grub_error (GRUB_ERR_BAD_DEVICE, "Device has no children"); do { /* XXX: Don't use hardcoded path lengths. */ char childtype[64]; char childpath[64]; char childname[64]; char fullname[64]; struct grub_ieee1275_devalias alias; int actual; if (grub_ieee1275_get_property (child, "device_type", &childtype, sizeof childtype, &actual)) continue; if (grub_ieee1275_package_to_path (child, childpath, sizeof childpath, &actual)) continue; if (grub_ieee1275_get_property (child, "name", &childname, sizeof childname, &actual)) continue; grub_sprintf (fullname, "%s/%s", devpath, childname); alias.type = childtype; alias.path = childpath; alias.name = fullname; hook (&alias); } while (grub_ieee1275_peer (child, &child)); return 0; }
static grub_err_t grub_ofdisk_open (const char *name, grub_disk_t disk) { grub_ieee1275_phandle_t dev; char *devpath; /* XXX: This should be large enough for any possible case. */ char prop[64]; grub_ssize_t actual; if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not IEEE1275 device"); devpath = compute_dev_path (name + sizeof ("ieee1275/") - 1); if (! devpath) return grub_errno; grub_dprintf ("disk", "Opening `%s'.\n", devpath); if (grub_ieee1275_finddevice (devpath, &dev)) { grub_free (devpath); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties"); } if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop), &actual)) { grub_free (devpath); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type"); } if (grub_strcmp (prop, "block")) { grub_free (devpath); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device"); } /* XXX: There is no property to read the number of blocks. There should be a property `#blocks', but it is not there. Perhaps it is possible to use seek for this. */ disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; { struct ofdisk_hash_ent *op; op = ofdisk_hash_find (devpath); if (!op) op = ofdisk_hash_add (devpath, NULL); else grub_free (devpath); if (!op) return grub_errno; disk->id = (unsigned long) op; disk->data = op->devpath; } return 0; }
static void grub_ieee1275_net_config_real (const char *devpath, char **device, char **path) { struct grub_net_card *card; /* FIXME: Check that it's the right card. */ FOR_NET_CARDS (card) { char *bootp_response; char *cardpath; char *canon; grub_ssize_t size = -1; unsigned int i; if (card->driver != &ofdriver) continue; cardpath = ((struct grub_ofnetcard_data *) card->data)->path; canon = grub_ieee1275_canonicalise_devname (cardpath); if (grub_strcmp (devpath, canon) != 0) { grub_free (canon); continue; } grub_free (canon); for (i = 0; i < ARRAY_SIZE (bootp_response_properties); i++) if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, bootp_response_properties[i].name, &size) >= 0) break; if (size < 0) return; bootp_response = grub_malloc (size); if (!bootp_response) { grub_print_error (); return; } if (grub_ieee1275_get_property (grub_ieee1275_chosen, bootp_response_properties[i].name, bootp_response, size, 0) < 0) return; grub_net_configure_by_dhcp_ack (card->name, card, 0, (struct grub_net_bootp_packet *) &bootp_response + bootp_response_properties[i].offset, size - bootp_response_properties[i].offset, 1, device, path); return; } }
static int grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, grub_disk_pull_t pull) { unsigned i; if (pull != GRUB_DISK_PULL_NONE) return 0; scan (); for (i = 0; i < ARRAY_SIZE (ofdisk_hash); i++) { static struct ofdisk_hash_ent *ent; for (ent = ofdisk_hash[i]; ent; ent = ent->next) { if (!ent->shortest) continue; if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY)) { grub_ieee1275_phandle_t dev; char tmp[8]; if (grub_ieee1275_finddevice (ent->devpath, &dev)) { grub_dprintf ("disk", "finddevice (%s) failed\n", ent->devpath); continue; } if (grub_ieee1275_get_property (dev, "iconname", tmp, sizeof tmp, 0)) { grub_dprintf ("disk", "get iconname failed\n"); continue; } if (grub_strcmp (tmp, "sdmmc") != 0) { grub_dprintf ("disk", "device is not an SD card\n"); continue; } } if (!ent->is_boot && ent->is_removable) continue; if (hook (ent->grub_shortest, hook_data)) return 1; } } return 0; }
void grub_machine_init (void) { char args[256]; grub_ssize_t actual; grub_ieee1275_init (); grub_console_init_early (); #ifdef __i386__ grub_get_extended_memory (); #endif grub_claim_heap (); grub_console_init_lately (); grub_ofdisk_init (); /* Process commandline. */ if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args, sizeof args, &actual) == 0 && actual > 1) { int i = 0; while (i < actual) { char *command = &args[i]; char *end; char *val; end = grub_strchr (command, ';'); if (end == 0) i = actual; /* No more commands after this one. */ else { *end = '\0'; i += end - command + 1; while (grub_isspace(args[i])) i++; } /* Process command. */ val = grub_strchr (command, '='); if (val) { *val = '\0'; grub_env_set (command, val + 1); } } } grub_install_get_time_ms (ieee1275_get_time_ms); }
int grub_ieee1275_get_integer_property (grub_ieee1275_phandle_t phandle, const char *property, grub_uint32_t *buf, grub_size_t size, grub_ssize_t *actual) { int ret; ret = grub_ieee1275_get_property (phandle, property, (void *) buf, size, actual); #ifndef GRUB_CPU_WORDS_BIGENDIAN /* Integer properties are always in big endian. */ if (ret == 0) { unsigned int i; size /= sizeof (grub_uint32_t); for (i = 0; i < size; i++) buf[i] = grub_be_to_cpu32 (buf[i]); } #endif return ret; }
void grub_machine_set_prefix (void) { if (grub_prefix[0] != '(') { char bootpath[IEEE1275_MAX_PATH_LEN]; char *prefix, *path, *colon; grub_ssize_t actual; if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", &bootpath, sizeof (bootpath), &actual)) { /* Should never happen. */ grub_printf ("/chosen/bootpath property missing!\n"); grub_env_set ("prefix", ""); return; } /* Transform an OF device path to a GRUB path. */ colon = grub_strchr (bootpath, ':'); if (colon) { char *part = colon + 1; /* Consistently provide numbered partitions to GRUB. OpenBOOT traditionally uses alphabetical partition specifiers. */ if (part[0] >= 'a' && part[0] <= 'z') part[0] = '1' + (part[0] - 'a'); } prefix = grub_ieee1275_encode_devname (bootpath); path = grub_xasprintf("%s%s", prefix, grub_prefix); grub_strcpy (grub_prefix, path); grub_free (path); grub_free (prefix); } grub_env_set ("prefix", grub_prefix); }
static int grub_ofdisk_iterate (int (*hook) (const char *name)) { auto int dev_iterate (struct grub_ieee1275_devalias *alias); int dev_iterate (struct grub_ieee1275_devalias *alias) { int ret = 0; grub_dprintf ("disk", "disk name = %s\n", alias->name); if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY)) { grub_ieee1275_phandle_t dev; char tmp[8]; if (grub_ieee1275_finddevice (alias->path, &dev)) { grub_dprintf ("disk", "finddevice (%s) failed\n", alias->path); return 0; } if (grub_ieee1275_get_property (dev, "iconname", tmp, sizeof tmp, 0)) { grub_dprintf ("disk", "get iconname failed\n"); return 0; } if (grub_strcmp (tmp, "sdmmc")) { grub_dprintf ("disk", "device is not an SD card\n"); return 0; } } if (! grub_strcmp (alias->type, "block") && grub_strncmp (alias->name, "cdrom", 5)) ret = hook (alias->name); return ret; }
int grub_ieee1275_alloc_physmem (grub_addr_t *paddr, grub_size_t size, grub_uint32_t align) { grub_uint32_t memory_ihandle; struct alloc_physmem_args { struct grub_ieee1275_common_hdr common; grub_ieee1275_cell_t method; grub_ieee1275_cell_t ihandle; grub_ieee1275_cell_t align; grub_ieee1275_cell_t size; grub_ieee1275_cell_t catch_result; grub_ieee1275_cell_t phys_high; grub_ieee1275_cell_t phys_low; } args; grub_ssize_t actual = 0; grub_ieee1275_get_property (grub_ieee1275_chosen, "memory", &memory_ihandle, sizeof (memory_ihandle), &actual); if (actual != sizeof (memory_ihandle)) return -1; if (!align) align = 1; INIT_IEEE1275_COMMON (&args.common, "call-method", 4, 3); args.method = (grub_ieee1275_cell_t) "claim"; args.ihandle = memory_ihandle; args.align = (align ? align : 1); args.size = size; if (IEEE1275_CALL_ENTRY_FN (&args) == -1) return -1; *paddr = args.phys_low; return args.catch_result; }
static void grub_parse_cmdline (void) { grub_ssize_t actual; char args[256]; if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args, sizeof args, &actual) == 0 && actual > 1) { int i = 0; while (i < actual) { char *command = &args[i]; char *end; char *val; end = grub_strchr (command, ';'); if (end == 0) i = actual; /* No more commands after this one. */ else { *end = '\0'; i += end - command + 1; while (grub_isspace(args[i])) i++; } /* Process command. */ val = grub_strchr (command, '='); if (val) { *val = '\0'; grub_env_set (command, val + 1); } } } }
static void insert_bootpath (void) { char *bootpath; grub_ssize_t bootpath_size; char *type; if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath", &bootpath_size) || bootpath_size <= 0) { /* Should never happen. */ grub_printf ("/chosen/bootpath property missing!\n"); return; } bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); if (! bootpath) { grub_print_error (); return; } grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath, (grub_size_t) bootpath_size + 1, 0); bootpath[bootpath_size] = '\0'; /* Transform an OF device path to a GRUB path. */ type = grub_ieee1275_get_device_type (bootpath); if (!(type && grub_strcmp (type, "network") == 0)) { struct ofdisk_hash_ent *op; char *device = grub_ieee1275_get_devname (bootpath); op = ofdisk_hash_add (device, NULL); op->is_boot = 1; } grub_free (type); grub_free (bootpath); }
/* Walk children of 'devpath', calling hook for each. */ int grub_children_iterate (char *devpath, int (*hook) (struct grub_ieee1275_devalias *alias, void *closure), void *closure) { grub_ieee1275_phandle_t dev; grub_ieee1275_phandle_t child; char *childtype, *childpath; char *childname; int ret = 0; if (grub_ieee1275_finddevice (devpath, &dev)) return 0; if (grub_ieee1275_child (dev, &child)) return 0; childtype = grub_malloc (IEEE1275_MAX_PROP_LEN); if (!childtype) return 0; childpath = grub_malloc (IEEE1275_MAX_PATH_LEN); if (!childpath) { grub_free (childtype); return 0; } childname = grub_malloc (IEEE1275_MAX_PROP_LEN); if (!childname) { grub_free (childpath); grub_free (childtype); return 0; } do { struct grub_ieee1275_devalias alias; grub_ssize_t actual; if (grub_ieee1275_get_property (child, "device_type", childtype, IEEE1275_MAX_PROP_LEN, &actual)) childtype[0] = 0; if (dev == child) continue; if (grub_ieee1275_package_to_path (child, childpath, IEEE1275_MAX_PATH_LEN, &actual)) continue; if (grub_strcmp (devpath, childpath) == 0) continue; if (grub_ieee1275_get_property (child, "name", childname, IEEE1275_MAX_PROP_LEN, &actual)) continue; alias.type = childtype; alias.path = childpath; alias.name = childname; ret = hook (&alias, closure); if (ret) break; } while (grub_ieee1275_peer (child, &child) != -1); grub_free (childname); grub_free (childpath); grub_free (childtype); return ret; }
static void grub_ieee1275_find_options (void) { grub_ieee1275_phandle_t root; grub_ieee1275_phandle_t options; grub_ieee1275_phandle_t openprom; grub_ieee1275_phandle_t bootrom; int rc; grub_uint32_t realmode = 0; char tmp[32]; int is_smartfirmware = 0; int is_olpc = 0; int is_qemu = 0; #ifdef __sparc__ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0); #endif grub_ieee1275_finddevice ("/", &root); grub_ieee1275_finddevice ("/options", &options); grub_ieee1275_finddevice ("/openprom", &openprom); rc = grub_ieee1275_get_integer_property (options, "real-mode?", &realmode, sizeof realmode, 0); if (((rc >= 0) && realmode) || (grub_ieee1275_mmu == 0)) grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_REAL_MODE); rc = grub_ieee1275_get_property (openprom, "CodeGen-copyright", tmp, sizeof (tmp), 0); if (rc >= 0 && !grub_strncmp (tmp, SF, sizeof (SF) - 1)) is_smartfirmware = 1; rc = grub_ieee1275_get_property (root, "architecture", tmp, sizeof (tmp), 0); if (rc >= 0 && !grub_strcmp (tmp, "OLPC")) is_olpc = 1; rc = grub_ieee1275_get_property (root, "model", tmp, sizeof (tmp), 0); if (rc >= 0 && !grub_strcmp (tmp, "Emulated PC")) is_qemu = 1; if (rc >= 0 && grub_strncmp (tmp, "IBM", 3) == 0) grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS); if (grub_strncmp (tmp, "PowerMac", sizeof ("PowerMac") - 1) == 0) grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS); if (is_smartfirmware) { /* Broken in all versions */ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_OUTPUT); /* There are two incompatible ways of checking the version number. Try both. */ rc = grub_ieee1275_get_property (openprom, "SmartFirmware-version", tmp, sizeof (tmp), 0); if (rc < 0) rc = grub_ieee1275_get_property (openprom, "firmware-version", tmp, sizeof (tmp), 0); if (rc >= 0) { /* It is tempting to implement a version parser to set the flags for e.g. 1.3 and below. However, there's a special situation here. 3rd party updates which fix the partition bugs are common, and for some reason their fixes aren't being merged into trunk. So for example we know that 1.2 and 1.3 are broken, but there's 1.2.99 and 1.3.99 which are known good (and applying this workaround would cause breakage). */ if (!grub_strcmp (tmp, "1.0") || !grub_strcmp (tmp, "1.1") || !grub_strcmp (tmp, "1.2") || !grub_strcmp (tmp, "1.3")) { grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0); grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_0_BASED_PARTITIONS); } } } if (is_olpc) { /* OLPC / XO laptops have three kinds of storage devices: - NAND flash. These are accessible via OFW callbacks, but: - Follow strange semantics, imposed by hardware constraints. - Its ABI is undocumented, and not stable. They lack "device_type" property, which conveniently makes GRUB skip them. - USB drives. Not accessible, because OFW shuts down the controller in order to prevent collisions with applications accessing it directly. Even worse, attempts to access it will NOT return control to the caller, so we have to avoid probing them. - SD cards. These work fine. To avoid breakage, we only need to skip USB probing. However, since detecting SD cards is more reliable, we do that instead. */ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY); grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF); } if (is_qemu) { /* OpenFirmware hangs on qemu if one requests any memory below 1.5 MiB. */ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM); grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF); } if (! grub_ieee1275_finddevice ("/rom/boot-rom", &bootrom)) { rc = grub_ieee1275_get_property (bootrom, "model", tmp, sizeof (tmp), 0); if (rc >= 0 && !grub_strncmp (tmp, OHW, sizeof (OHW) - 1)) { grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_OUTPUT); grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_SET_COLORS); grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET); grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM); grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_ANSI); } } }
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 *ret = 0; grub_ieee1275_phandle_t dev; /* 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", 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", device); goto fail; } switch (ptype) { case GRUB_PARSE_DEVICE: ret = grub_strdup (device); break; case GRUB_PARSE_DEVICE_TYPE: ret = grub_strdup (type); break; case GRUB_PARSE_FILENAME: { char *comma; char *args; if (grub_strcmp ("block", type) != 0) goto unknown; args = grub_ieee1275_get_devargs (path); if (!args) /* Shouldn't happen. */ return 0; /* The syntax of the device arguments is defined in the CHRP and PReP IEEE1275 bindings: "[partition][,[filename]]". */ comma = grub_strchr (args, ','); if (comma) { char *filepath = comma + 1; /* Make sure filepath has leading backslash. */ if (filepath[0] != '\\') ret = grub_xasprintf ("\\%s", filepath); else ret = grub_strdup (filepath); } grub_free (args); } break; case GRUB_PARSE_PARTITION: { char *comma; char *args; if (grub_strcmp ("block", type) != 0) goto unknown; args = grub_ieee1275_get_devargs (path); if (!args) /* Shouldn't happen. */ return 0; comma = grub_strchr (args, ','); if (!comma) ret = grub_strdup (args); else ret = grub_strndup (args, (grub_size_t)(comma - args)); /* Consistently provide numbered partitions to GRUB. OpenBOOT traditionally uses alphabetical partition specifiers. */ if (ret[0] >= 'a' && ret[0] <= 'z') ret[0] = '1' + (ret[0] - 'a'); grub_free (args); } break; default: unknown: grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported type %s for device %s", type, device); } fail: grub_free (device); return ret; }
/* 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)) { grub_ieee1275_phandle_t aliases; char aliasname[32]; int actual; struct grub_ieee1275_devalias alias; if (grub_ieee1275_finddevice ("/aliases", &aliases)) return -1; /* Find the first property. */ aliasname[0] = '\0'; while (grub_ieee1275_next_property (aliases, aliasname, aliasname)) { grub_ieee1275_phandle_t dev; grub_ssize_t pathlen; char *devpath; /* XXX: This should be large enough for any possible case. */ char devtype[64]; grub_dprintf ("devalias", "devalias name = %s\n", aliasname); grub_ieee1275_get_property_length (aliases, aliasname, &pathlen); /* The property `name' is a special case we should skip. */ if (!grub_strcmp (aliasname, "name")) continue; devpath = grub_malloc (pathlen); if (! devpath) return grub_errno; if (grub_ieee1275_get_property (aliases, aliasname, devpath, pathlen, &actual)) { grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname); goto nextprop; } if (grub_ieee1275_finddevice (devpath, &dev)) { grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath); goto nextprop; } if (grub_ieee1275_get_property (dev, "device_type", devtype, sizeof devtype, &actual)) { /* NAND device don't have device_type property. */ devtype[0] = 0; } alias.name = aliasname; alias.path = devpath; alias.type = devtype; hook (&alias); nextprop: grub_free (devpath); } return 0; }
void grub_machine_get_bootlocation (char **device, char **path) { char *bootpath; grub_ssize_t bootpath_size; char *filename; char *type; if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath", &bootpath_size) || bootpath_size <= 0) { /* Should never happen. */ grub_printf ("/chosen/bootpath property missing!\n"); return; } bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); if (! bootpath) { grub_print_error (); return; } grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath, (grub_size_t) bootpath_size + 1, 0); bootpath[bootpath_size] = '\0'; /* Transform an OF device path to a GRUB path. */ type = grub_ieee1275_get_device_type (bootpath); if (type && grub_strcmp (type, "network") == 0) { char *dev, *canon; char *ptr; dev = grub_ieee1275_get_aliasdevname (bootpath); canon = grub_ieee1275_canonicalise_devname (dev); ptr = canon + grub_strlen (canon) - 1; while (ptr > canon && (*ptr == ',' || *ptr == ':')) ptr--; ptr++; *ptr = 0; if (grub_ieee1275_net_config) grub_ieee1275_net_config (canon, device, path, bootpath); grub_free (dev); grub_free (canon); } else *device = grub_ieee1275_encode_devname (bootpath); grub_free (type); filename = grub_ieee1275_get_filename (bootpath); if (filename) { char *lastslash = grub_strrchr (filename, '\\'); /* Truncate at last directory. */ if (lastslash) { *lastslash = '\0'; grub_translate_ieee1275_path (filename); *path = filename; } } grub_free (bootpath); }
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:<server ip>,<file name>,<client ip>,<gateway ip>,<bootp retries>,<tftp retries>". */ grub_printf ("Unsupported type %s for device %s\n", type, device); } fail: grub_free (device); grub_free (args); return ret; }
grub_err_t grub_machine_mmap_iterate (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t, void *closure), void *closure) { grub_ieee1275_phandle_t root; grub_ieee1275_phandle_t memory; grub_uint32_t available[32]; grub_ssize_t available_size; grub_uint32_t address_cells = 1; grub_uint32_t size_cells = 1; char copyright[128]; int i; /* Determine the format of each entry in `available'. */ grub_ieee1275_finddevice ("/", &root); grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells, sizeof address_cells, 0); grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells, sizeof size_cells, 0); grub_ieee1275_get_property (root, "copyright", copyright, sizeof copyright, 0); if (size_cells > address_cells) address_cells = size_cells; /* Apple ppc g4, g5 /memory/available[] uses 32bit offset and size, including for >4GB fitted RAM, and does not use root cell sizes. Maybe some other ieee1275 Apple uses 64bit offset and size? */ if (grub_strstr (copyright, "Apple")) address_cells = size_cells; /* Load `/memory/available'. */ if (grub_ieee1275_finddevice ("/memory", &memory)) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find /memory node"); if (grub_ieee1275_get_integer_property (memory, "available", available, sizeof available, &available_size)) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /memory/available property"); /* Decode each entry and call `hook'. */ i = 0; available_size /= sizeof (grub_uint32_t); while (i < available_size) { grub_uint64_t address; grub_uint64_t size; address = available[i++]; if (address_cells == 2) address = (address << 32) | available[i++]; size = available[i++]; if (size_cells == 2) size = (size << 32) | available[i++]; if (hook (address, size, GRUB_MACHINE_MEMORY_AVAILABLE, closure)) break; } return grub_errno; }
static grub_err_t grub_ofdisk_open (const char *name, grub_disk_t disk) { grub_ieee1275_phandle_t dev; grub_ieee1275_ihandle_t dev_ihandle = 0; struct ofdisk_hash_ent *op; char *devpath; /* XXX: This should be large enough for any possible case. */ char prop[64]; grub_ssize_t actual; devpath = compute_dev_path (name); if (! devpath) return grub_errno; op = ofdisk_hash_find (devpath); if (!op) op = ofdisk_hash_add (devpath); grub_free (devpath); if (!op) return grub_errno; if (op->dev_ihandle) { op->refs++; /* XXX: There is no property to read the number of blocks. There should be a property `#blocks', but it is not there. Perhaps it is possible to use seek for this. */ disk->total_sectors = 0xFFFFFFFFUL; disk->id = (unsigned long) op; /* XXX: Read this, somehow. */ disk->has_partitions = 1; disk->data = op; return 0; } grub_dprintf ("disk", "Opening `%s'.\n", op->devpath); if (grub_ieee1275_finddevice (op->devpath, &dev)) { grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties"); goto fail; } if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop), &actual)) { grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type"); goto fail; } if (grub_strcmp (prop, "block")) { grub_error (GRUB_ERR_BAD_DEVICE, "not a block device"); goto fail; } grub_ieee1275_open (op->devpath, &dev_ihandle); if (! dev_ihandle) { grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); goto fail; } grub_dprintf ("disk", "Opened `%s' as handle %p.\n", op->devpath, (void *) (unsigned long) dev_ihandle); op->dev_ihandle = dev_ihandle; op->refs++; /* XXX: There is no property to read the number of blocks. There should be a property `#blocks', but it is not there. Perhaps it is possible to use seek for this. */ disk->total_sectors = 0xFFFFFFFFUL; disk->id = (unsigned long) op; /* XXX: Read this, somehow. */ disk->has_partitions = 1; disk->data = op; return 0; fail: if (dev_ihandle) grub_ieee1275_close (dev_ihandle); return grub_errno; }
static void grub_ofnet_findcards (void) { auto int search_net_devices (struct grub_ieee1275_devalias *alias); int search_net_devices (struct grub_ieee1275_devalias *alias) { if (!grub_strcmp (alias->type, "network")) { struct grub_ofnetcard_data *ofdata; struct grub_net_card *card; grub_ieee1275_phandle_t devhandle; grub_net_link_level_address_t lla; char *shortname; ofdata = grub_malloc (sizeof (struct grub_ofnetcard_data)); if (!ofdata) { grub_print_error (); return 1; } card = grub_zalloc (sizeof (struct grub_net_card)); if (!card) { grub_free (ofdata); grub_print_error (); return 1; } ofdata->path = grub_strdup (alias->path); grub_ieee1275_finddevice (ofdata->path, &devhandle); if (grub_ieee1275_get_integer_property (devhandle, "max-frame-size", &(ofdata->mtu), sizeof (ofdata->mtu), 0)) { ofdata->mtu = 1500; } if (grub_ieee1275_get_property (devhandle, "mac-address", &(lla.mac), 6, 0) && grub_ieee1275_get_property (devhandle, "local-mac-address", &(lla.mac), 6, 0)) { grub_error (GRUB_ERR_IO, "Couldn't retrieve mac address."); grub_print_error (); return 0; } lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; card->default_address = lla; card->driver = NULL; card->data = ofdata; card->flags = 0; shortname = find_alias (alias->path); card->name = grub_xasprintf ("ofnet_%s", shortname ? : alias->path); card->idle_poll_delay_ms = 1; grub_free (shortname); card->driver = &ofdriver; grub_net_card_register (card); return 0; } return 0; } /* Look at all nodes for devices of the type network. */ grub_ieee1275_devices_iterate (search_net_devices); }
/* Iterate through all device aliases. This function can be used to find a device of a specific type. */ int grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias, void *closure), void *closure) { grub_ieee1275_phandle_t aliases; char *aliasname, *devtype; grub_ssize_t actual; struct grub_ieee1275_devalias alias; int ret = 0; if (grub_ieee1275_finddevice ("/aliases", &aliases)) return 0; aliasname = grub_malloc (IEEE1275_MAX_PROP_LEN); if (!aliasname) return 0; devtype = grub_malloc (IEEE1275_MAX_PROP_LEN); if (!devtype) { grub_free (aliasname); return 0; } /* Find the first property. */ aliasname[0] = '\0'; while (grub_ieee1275_next_property (aliases, aliasname, aliasname) > 0) { grub_ieee1275_phandle_t dev; grub_ssize_t pathlen; char *devpath; if (! aliasname[0]) break; grub_dprintf ("devalias", "devalias name = %s\n", aliasname); grub_ieee1275_get_property_length (aliases, aliasname, &pathlen); /* The property `name' is a special case we should skip. */ if (!grub_strcmp (aliasname, "name")) continue; /* Sun's OpenBoot often doesn't zero terminate the device alias strings, so we will add a NULL byte at the end explicitly. */ pathlen += 1; devpath = grub_malloc (pathlen); if (! devpath) { grub_free (devtype); grub_free (aliasname); return 0; } if (grub_ieee1275_get_property (aliases, aliasname, devpath, pathlen, &actual)) { grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname); goto nextprop; } devpath [actual] = '\0'; if (grub_ieee1275_finddevice (devpath, &dev)) { grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath); goto nextprop; } if (grub_ieee1275_get_property (dev, "device_type", devtype, IEEE1275_MAX_PROP_LEN, &actual)) { /* NAND device don't have device_type property. */ devtype[0] = 0; } alias.name = aliasname; alias.path = devpath; alias.type = devtype; ret = hook (&alias, closure); nextprop: grub_free (devpath); if (ret) break; } grub_free (devtype); grub_free (aliasname); return ret; }