/* Load a directory containing kexts. */ static grub_err_t grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)), int argc, char *args[]) { if (argc != 1 && argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory name required"); if (argc == 1) return grub_xnu_scan_dir_for_kexts (args[0], "console,root,local-root,network-root", 10); else { char *osbundlerequired = grub_strdup (args[1]), *ptr; grub_err_t err; if (! osbundlerequired) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate string temporary space"); for (ptr = osbundlerequired; *ptr; ptr++) *ptr = grub_tolower (*ptr); err = grub_xnu_scan_dir_for_kexts (args[0], osbundlerequired, 10); grub_free (osbundlerequired); return err; } }
grub_err_t strtou64_h(const char *str, U64 * value_ret) { U64 value; int base = 0; char *end; const char *last = str + grub_strlen(str) - 1; if (last < str) return grub_error(GRUB_ERR_BAD_NUMBER, "Unrecognized number"); if (grub_tolower(*last) == 'h') { base = 16; last--; if (last < str) return grub_error(GRUB_ERR_BAD_NUMBER, "Unrecognized number"); } value = grub_strtoull(str, &end, base); if (grub_errno != GRUB_ERR_NONE || end != (last + 1)) { return grub_error(GRUB_ERR_BAD_NUMBER, "Unrecognized number"); } else { *value_ret = value; return GRUB_ERR_NONE; } }
/* Returns true if the kext should be loaded according to plist and osbundlereq. Also fill BINNAME. */ static int grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq, char **binname) { grub_file_t file; char *buf = 0, *tagstart = 0, *ptr1 = 0, *keyptr = 0; char *stringptr = 0, *ptr2 = 0; grub_size_t size; int depth = 0; int ret; int osbundlekeyfound = 0, binnamekeyfound = 0; if (binname) *binname = 0; file = grub_gzfile_open (plistname, 1); if (! file) { grub_file_close (file); grub_error_push (); grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname); return 0; } size = grub_file_size (file); buf = grub_malloc (size); if (! buf) { grub_file_close (file); grub_error_push (); grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read file %s", plistname); return 0; } if (grub_file_read (file, buf, size) != (grub_ssize_t) (size)) { grub_file_close (file); grub_error_push (); grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname); return 0; } grub_file_close (file); /* Set the return value for the case when no OSBundleRequired tag is found. */ if (osbundlereq) ret = grub_strword (osbundlereq, "all") || grub_strword (osbundlereq, "-"); else ret = 1; /* Parse plist. It's quite dirty and inextensible but does its job. */ for (ptr1 = buf; ptr1 < buf + size; ptr1++) switch (*ptr1) { case '<': tagstart = ptr1; *ptr1 = 0; if (keyptr && depth == 4 && grub_strcmp (keyptr, "OSBundleRequired") == 0) osbundlekeyfound = 1; if (keyptr && depth == 4 && grub_strcmp (keyptr, "CFBundleExecutable") == 0) binnamekeyfound = 1; if (stringptr && osbundlekeyfound && osbundlereq && depth == 4) { for (ptr2 = stringptr; *ptr2; ptr2++) *ptr2 = grub_tolower (*ptr2); ret = grub_strword (osbundlereq, stringptr) || grub_strword (osbundlereq, "all"); } if (stringptr && binnamekeyfound && binname && depth == 4) { if (*binname) grub_free (*binname); *binname = grub_strdup (stringptr); } *ptr1 = '<'; keyptr = 0; stringptr = 0; break; case '>': if (! tagstart) { grub_free (buf); grub_error (GRUB_ERR_BAD_OS, "can't parse %s", plistname); return 0; } *ptr1 = 0; if (tagstart[1] == '?' || ptr1[-1] == '/') { osbundlekeyfound = 0; *ptr1 = '>'; break; } if (depth == 3 && grub_strcmp (tagstart + 1, "key") == 0) keyptr = ptr1 + 1; if (depth == 3 && grub_strcmp (tagstart + 1, "string") == 0) stringptr = ptr1 + 1; else if (grub_strcmp (tagstart + 1, "/key") != 0) { osbundlekeyfound = 0; binnamekeyfound = 0; } *ptr1 = '>'; if (tagstart[1] == '/') depth--; else depth++; break; } grub_free (buf); return ret; }
unsigned long long grub_strtoull (const char *str, char **end, int base) { unsigned long long num = 0; int found = 0; /* Skip white spaces. */ while (*str && grub_isspace (*str)) str++; /* Guess the base, if not specified. The prefix `0x' means 16, and the prefix `0' means 8. */ if (str[0] == '0') { if (str[1] == 'x') { if (base == 0 || base == 16) { base = 16; str += 2; } } else if (base == 0 && str[1] >= '0' && str[1] <= '7') base = 8; } if (base == 0) base = 10; while (*str) { unsigned long digit; digit = grub_tolower (*str) - '0'; if (digit > 9) { digit += '0' - 'a' + 10; if (digit >= (unsigned long) base) break; } found = 1; /* NUM * BASE + DIGIT > ~0ULL */ if (num > grub_divmod64 (~0ULL - digit, base, 0)) { grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected"); return ~0ULL; } num = num * base + digit; str++; } if (! found) { grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number"); return 0; } if (end) *end = (char *) str; return num; }
static grub_err_t grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) { struct grub_arg_list *state = ctxt->state; struct grub_acpi_rsdp_v10 *rsdp; struct efiemu_acpi_table *cur, *t; int i, mmapregion; int numoftables; /* Default values if no RSDP is found. */ rev1 = 1; rev2 = 3; facs_addr = 0; playground = playground_ptr = 0; playground_size = 0; rsdp = (struct grub_acpi_rsdp_v10 *) grub_machine_acpi_get_rsdpv2 (); if (! rsdp) rsdp = grub_machine_acpi_get_rsdpv1 (); if (rsdp) { grub_uint32_t *entry_ptr; char *exclude = 0; char *load_only = 0; char *ptr; /* RSDT consists of header and an array of 32-bit pointers. */ struct grub_acpi_table_header *rsdt; exclude = state[0].set ? grub_strdup (state[0].arg) : 0; if (exclude) { for (ptr = exclude; *ptr; ptr++) *ptr = grub_tolower (*ptr); } load_only = state[1].set ? grub_strdup (state[1].arg) : 0; if (load_only) { for (ptr = load_only; *ptr; ptr++) *ptr = grub_tolower (*ptr); } /* Set revision variables to replicate the same version as host. */ rev1 = ! rsdp->revision; rev2 = rsdp->revision; rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp->rsdt_addr; /* Load host tables. */ for (entry_ptr = (grub_uint32_t *) (rsdt + 1); entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt) + rsdt->length); entry_ptr++) { char signature[5]; struct efiemu_acpi_table *table; struct grub_acpi_table_header *curtable = (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr; signature[4] = 0; for (i = 0; i < 4;i++) signature[i] = grub_tolower (curtable->signature[i]); /* If it's FADT it contains addresses of DSDT and FACS. */ if (grub_strcmp (signature, "facp") == 0) { struct grub_acpi_table_header *dsdt; struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable; /* Set root header variables to the same values as FADT by default. */ grub_memcpy (&root_oemid, &(fadt->hdr.oemid), sizeof (root_oemid)); grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable), sizeof (root_oemtable)); root_oemrev = fadt->hdr.oemrev; grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id), sizeof (root_creator_id)); root_creator_rev = fadt->hdr.creator_rev; /* Load DSDT if not excluded. */ dsdt = (struct grub_acpi_table_header *) (grub_addr_t) fadt->dsdt_addr; if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt")) && (! load_only || grub_strword (load_only, "dsdt")) && dsdt->length >= sizeof (*dsdt)) { dsdt_size = dsdt->length; table_dsdt = grub_malloc (dsdt->length); if (! table_dsdt) { free_tables (); grub_free (exclude); grub_free (load_only); return grub_errno; } grub_memcpy (table_dsdt, dsdt, dsdt->length); } /* Save FACS address. FACS shouldn't be overridden. */ facs_addr = fadt->facs_addr; } /* Skip excluded tables. */ if (exclude && grub_strword (exclude, signature)) continue; if (load_only && ! grub_strword (load_only, signature)) continue; /* Sanity check. */ if (curtable->length < sizeof (*curtable)) continue; table = (struct efiemu_acpi_table *) grub_malloc (sizeof (struct efiemu_acpi_table)); if (! table) { free_tables (); grub_free (exclude); grub_free (load_only); return grub_errno; } table->size = curtable->length; table->addr = grub_malloc (table->size); playground_size += table->size; if (! table->addr) { free_tables (); return grub_errno; } table->next = acpi_tables; acpi_tables = table; grub_memcpy (table->addr, curtable, table->size); } grub_free (exclude); grub_free (load_only); } /* Does user specify versions to generate? */ if (state[2].set || state[3].set) { rev1 = state[2].set; if (state[3].set) rev2 = rev2 ? : 2; else
static int grub_iso9660_iterate_dir (grub_fshelp_node_t dir, grub_fshelp_iterate_dir_hook_t hook, void *hook_data) { struct grub_iso9660_dir dirent; grub_off_t offset = 0; grub_off_t len; struct iterate_dir_ctx ctx; len = get_node_size (dir); for (; offset < len; offset += dirent.len) { ctx.symlink = 0; ctx.was_continue = 0; if (read_node (dir, offset, sizeof (dirent), (char *) &dirent)) return 0; /* The end of the block, skip to the next one. */ if (!dirent.len) { offset = (offset / GRUB_ISO9660_BLKSZ + 1) * GRUB_ISO9660_BLKSZ; continue; } { char name[MAX_NAMELEN + 1]; int nameoffset = offset + sizeof (dirent); struct grub_fshelp_node *node; int sua_off = (sizeof (dirent) + dirent.namelen + 1 - (dirent.namelen % 2)); int sua_size = dirent.len - sua_off; sua_off += offset + dir->data->susp_skip; ctx.filename = 0; ctx.filename_alloc = 0; ctx.type = GRUB_FSHELP_UNKNOWN; if (dir->data->rockridge && grub_iso9660_susp_iterate (dir, sua_off, sua_size, susp_iterate_dir, &ctx)) return 0; /* Read the name. */ if (read_node (dir, nameoffset, dirent.namelen, (char *) name)) return 0; node = grub_malloc (sizeof (struct grub_fshelp_node)); if (!node) return 0; node->alloc_dirents = ARRAY_SIZE (node->dirents); node->have_dirents = 1; /* Setup a new node. */ node->data = dir->data; node->have_symlink = 0; /* If the filetype was not stored using rockridge, use whatever is stored in the iso9660 filesystem. */ if (ctx.type == GRUB_FSHELP_UNKNOWN) { if ((dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR) ctx.type = GRUB_FSHELP_DIR; else ctx.type = GRUB_FSHELP_REG; } /* . and .. */ if (!ctx.filename && dirent.namelen == 1 && name[0] == 0) ctx.filename = (char *) "."; if (!ctx.filename && dirent.namelen == 1 && name[0] == 1) ctx.filename = (char *) ".."; /* The filename was not stored in a rock ridge entry. Read it from the iso9660 filesystem. */ if (!dir->data->joliet && !ctx.filename) { char *ptr; name[dirent.namelen] = '\0'; ctx.filename = grub_strrchr (name, ';'); if (ctx.filename) *ctx.filename = '\0'; /* ISO9660 names are not case-preserving. */ ctx.type |= GRUB_FSHELP_CASE_INSENSITIVE; for (ptr = name; *ptr; ptr++) *ptr = grub_tolower (*ptr); if (ptr != name && *(ptr - 1) == '.') *(ptr - 1) = 0; ctx.filename = name; } if (dir->data->joliet && !ctx.filename) { char *semicolon; ctx.filename = grub_iso9660_convert_string ((grub_uint8_t *) name, dirent.namelen >> 1); semicolon = grub_strrchr (ctx.filename, ';'); if (semicolon) *semicolon = '\0'; ctx.filename_alloc = 1; } node->dirents[0] = dirent; while (dirent.flags & FLAG_MORE_EXTENTS) { offset += dirent.len; if (read_node (dir, offset, sizeof (dirent), (char *) &dirent)) { if (ctx.filename_alloc) grub_free (ctx.filename); grub_free (node); return 0; } if (node->have_dirents >= node->alloc_dirents) { struct grub_fshelp_node *new_node; node->alloc_dirents *= 2; new_node = grub_realloc (node, sizeof (struct grub_fshelp_node) + ((node->alloc_dirents - ARRAY_SIZE (node->dirents)) * sizeof (node->dirents[0]))); if (!new_node) { if (ctx.filename_alloc) grub_free (ctx.filename); grub_free (node); return 0; } node = new_node; } node->dirents[node->have_dirents++] = dirent; } if (ctx.symlink) { if ((node->alloc_dirents - node->have_dirents) * sizeof (node->dirents[0]) < grub_strlen (ctx.symlink) + 1) { struct grub_fshelp_node *new_node; new_node = grub_realloc (node, sizeof (struct grub_fshelp_node) + ((node->alloc_dirents - ARRAY_SIZE (node->dirents)) * sizeof (node->dirents[0])) + grub_strlen (ctx.symlink) + 1); if (!new_node) { if (ctx.filename_alloc) grub_free (ctx.filename); grub_free (node); return 0; } node = new_node; } node->have_symlink = 1; grub_strcpy (node->symlink + node->have_dirents * sizeof (node->dirents[0]) - sizeof (node->dirents), ctx.symlink); grub_free (ctx.symlink); ctx.symlink = 0; ctx.was_continue = 0; } if (hook (ctx.filename, ctx.type, node, hook_data)) { if (ctx.filename_alloc) grub_free (ctx.filename); return 1; } if (ctx.filename_alloc) grub_free (ctx.filename); } }
int uefi_dir (char *dirname) { grub_efi_status_t status; grub_efi_char16_t *file_name_w = NULL; grub_efi_char16_t *dir_name_w = NULL; grub_efi_file_info_t *fileinfo = NULL; grub_efi_uintn_t buffersize = 0; grub_efi_file_t *directory = NULL; int i, dirlen = 0, ret = 0; file_name_w = grub_malloc (2 * strlen(dirname) + 2); if (!file_name_w) goto done; for (i=0; i<strlen(dirname); i++) { file_name_w[i] = dirname[i]; if (file_name_w[i] == '/') { file_name_w[i] = '\\'; dirlen = i; } } file_name_w[i] = '\0'; status = Call_Service_5 (root->open, root, &file, file_name_w, GRUB_EFI_FILE_MODE_READ, 0); if (status != GRUB_EFI_SUCCESS) goto done; if (dirname[i-1] == '/') { if (print_possibilities) grub_printf("\n"); while (1) { int filenamelen; status = Call_Service_3 (file->read, file, &buffersize, fileinfo); if (status == GRUB_EFI_BUFFER_TOO_SMALL) { fileinfo = grub_malloc(buffersize); continue; } else if (status) { goto done; } else if (buffersize == 0) { ret = 1; if (print_possibilities) grub_printf("\n"); goto done; } filenamelen = fileinfo->size - sizeof(*fileinfo); if (print_possibilities) { for (i=0; i<filenamelen/2; i++) grub_printf("%c", (char)fileinfo->filename[i]); } grub_printf(" "); } } else { char *data = NULL; dir_name_w = grub_malloc (2 * dirlen + 2); if (!dir_name_w) goto done; for (i=0; i<dirlen; i++) dir_name_w[i] = file_name_w[i]; dir_name_w[i] = '\0'; status = Call_Service_5 (root->open, root, &directory, dir_name_w, GRUB_EFI_FILE_MODE_READ, 0); while (1) { int filenamelen; int invalid = 0; status = Call_Service_3 (directory->read, directory, &buffersize, fileinfo); if (status == GRUB_EFI_BUFFER_TOO_SMALL) { fileinfo = grub_malloc(buffersize); continue; } else if (status) { goto done; } else if (buffersize == 0) { goto done; } filenamelen = fileinfo->size - sizeof(*fileinfo); if (filenamelen != ((strlen(dirname) - dirlen) * 2)) continue; for (i=0; i<filenamelen/2; i++) { if (fileinfo->filename[i] != file_name_w[i + dirlen + 1]) { if (fileinfo->filename[i] > 0xff || (grub_tolower(fileinfo->filename[i]) != grub_tolower(file_name_w[i + dirlen + 1]))) invalid = 1; } } if (!invalid) break; } if (fileinfo->filesize < 256 && fileinfo->filesize > 3) { data = grub_malloc(fileinfo->filesize); filepos = 0; uefi_read(data, fileinfo->filesize); /* * UEFI doesn't really support symlinks. Apple's UEFI driver exposes * them as files containing the path of the target. This provides * hacky support in the absence of a real driver. */ if (data[0] == '.' && data[1] == '.' && data[2] == '/') { int j; char *tmpdir = grub_malloc(dirlen + fileinfo->filesize); for (j=0; j<dirlen+1; j++) tmpdir[j] = dirname[j]; for (j=0; j<fileinfo->filesize; j++) tmpdir[j+dirlen+1] = data[j]; tmpdir[j+dirlen+1] = '\0'; /* Open the new file */ ret = uefi_dir(tmpdir); grub_free (tmpdir); grub_free (data); goto done; } } if (data) grub_free(data); ret = 1; filemax = fileinfo->filesize; filepos = 0; } done: if (fileinfo) grub_free (fileinfo); if (dir_name_w) grub_free (dir_name_w); if (file_name_w) grub_free (file_name_w); return ret; }