/* Load the kext. */ static grub_err_t grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)), int argc, char *args[]) { grub_file_t binfile = 0; if (argc == 2) { /* User explicitly specified plist and binary. */ if (grub_strcmp (args[1], "-") != 0) { binfile = grub_gzfile_open (args[1], 1); if (! binfile) { grub_error (GRUB_ERR_BAD_OS, "can't open file"); return GRUB_ERR_NONE; } } return grub_xnu_load_driver (grub_strcmp (args[0], "-") ? args[0] : 0, binfile); } /* load kext normally. */ if (argc == 1) return grub_xnu_load_kext_from_dir (args[0], 0, 10); return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); }
/* This is similar to grub_gzfile_open. */ static grub_file_t grub_mofile_open (const char *filename) { int unsigned magic; int version; /* Using fd_mo and not another variable because it's needed for grub_gettext_get_info. */ fd_mo = grub_gzfile_open (filename, 1); grub_errno = GRUB_ERR_NONE; if (!fd_mo) { grub_dprintf ("gettext", "Cannot read %s\n", filename); return 0; } magic = grub_gettext_get_info (GETTEXT_MAGIC_NUMBER); if (magic != MO_MAGIC_NUMBER) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "mo: invalid mo file: %s", filename); grub_file_close (fd_mo); fd_mo = 0; return 0; } version = grub_gettext_get_info (GETTEXT_FILE_FORMAT); if (version != 0) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "mo: invalid mo version in file: %s", filename); fd_mo = 0; return 0; } return fd_mo; }
static grub_err_t grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), int argc, char *args[]) { grub_file_t file; void *loadto; grub_err_t err; grub_size_t size; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); file = grub_gzfile_open (args[0], 1); if (! file) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't load ramdisk"); err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) return err; size = grub_file_size (file); loadto = grub_xnu_heap_malloc (size); if (! loadto) return grub_errno; if (grub_file_read (file, loadto, size) != (grub_ssize_t) (size)) { grub_file_close (file); grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); } return grub_xnu_register_memory ("RAMDisk", 0, loadto, size); }
/* 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; }
/* Load mkext. */ static grub_err_t grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), int argc, char *args[]) { grub_file_t file; void *loadto; grub_err_t err; grub_off_t readoff = 0; grub_ssize_t readlen = -1; struct grub_macho_fat_header head; struct grub_macho_fat_arch *archs; int narchs, i; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); file = grub_gzfile_open (args[0], 1); if (! file) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't load driver package"); /* Sometimes caches are fat binary. Errgh. */ if (grub_file_read (file, &head, sizeof (head)) != (grub_ssize_t) (sizeof (head))) { /* I don't know the internal structure of package but can hardly imagine a valid package shorter than 20 bytes. */ grub_file_close (file); grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); } /* Find the corresponding architecture. */ if (grub_be_to_cpu32 (head.magic) == GRUB_MACHO_FAT_MAGIC) { narchs = grub_be_to_cpu32 (head.nfat_arch); archs = grub_malloc (sizeof (struct grub_macho_fat_arch) * narchs); if (! archs) { grub_file_close (file); grub_error_push (); return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read file %s", args[0]); } if (grub_file_read (file, archs, sizeof (struct grub_macho_fat_arch) * narchs) != (grub_ssize_t) sizeof(struct grub_macho_fat_arch) * narchs) { grub_free (archs); grub_error_push (); return grub_error (GRUB_ERR_READ_ERROR, "cannot read fat header"); } for (i = 0; i < narchs; i++) { if (!grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32 (grub_be_to_cpu32 (archs[i].cputype))) { readoff = grub_be_to_cpu32 (archs[i].offset); readlen = grub_be_to_cpu32 (archs[i].size); } if (grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64 (grub_be_to_cpu32 (archs[i].cputype))) { readoff = grub_be_to_cpu32 (archs[i].offset); readlen = grub_be_to_cpu32 (archs[i].size); } } grub_free (archs); } else { /* It's a flat file. Some sane people still exist. */ readoff = 0; readlen = grub_file_size (file); } if (readlen == -1) { grub_file_close (file); return grub_error (GRUB_ERR_BAD_OS, "no suitable architecture is found"); } /* Allocate space. */ err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) { grub_file_close (file); return err; } loadto = grub_xnu_heap_malloc (readlen); if (! loadto) { grub_file_close (file); return grub_errno; } /* Read the file. */ grub_file_seek (file, readoff); if (grub_file_read (file, loadto, readlen) != (grub_ssize_t) (readlen)) { grub_file_close (file); grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); } grub_file_close (file); /* Pass it to kernel. */ return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum, loadto, readlen); }
/* Load .kext. */ static grub_err_t grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) { grub_macho_t macho; grub_err_t err; grub_file_t infoplist; struct grub_xnu_extheader *exthead; int neededspace = sizeof (*exthead); grub_uint8_t *buf; grub_size_t infoplistsize = 0, machosize = 0; char *name, *nameend; int namelen; name = get_name_ptr (infoplistname); nameend = grub_strchr (name, '/'); if (nameend) namelen = nameend - name; else namelen = grub_strlen (name); neededspace += namelen + 1; if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); /* Compute the needed space. */ if (binaryfile) { macho = grub_macho_file (binaryfile); if (! macho || ! grub_macho_contains_macho32 (macho)) { if (macho) grub_macho_close (macho); return grub_error (GRUB_ERR_BAD_OS, "extension doesn't contain suitable architecture"); } if (grub_xnu_is_64bit) machosize = grub_macho_filesize64 (macho); else machosize = grub_macho_filesize32 (macho); neededspace += machosize; } else macho = 0; if (infoplistname) infoplist = grub_gzfile_open (infoplistname, 1); else infoplist = 0; grub_errno = GRUB_ERR_NONE; if (infoplist) { infoplistsize = grub_file_size (infoplist); neededspace += infoplistsize + 1; } else infoplistsize = 0; /* Allocate the space. */ err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) return err; buf = grub_xnu_heap_malloc (neededspace); exthead = (struct grub_xnu_extheader *) buf; grub_memset (exthead, 0, sizeof (*exthead)); buf += sizeof (*exthead); /* Load the binary. */ if (macho) { exthead->binaryaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) + grub_xnu_heap_will_be_at; exthead->binarysize = machosize; if (grub_xnu_is_64bit) err = grub_macho_readfile64 (macho, buf); else err = grub_macho_readfile32 (macho, buf); if (err) { grub_macho_close (macho); return err; } grub_macho_close (macho); buf += machosize; } grub_errno = GRUB_ERR_NONE; /* Load the plist. */ if (infoplist) { exthead->infoplistaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) + grub_xnu_heap_will_be_at; exthead->infoplistsize = infoplistsize + 1; if (grub_file_read (infoplist, buf, infoplistsize) != (grub_ssize_t) (infoplistsize)) { grub_file_close (infoplist); grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s: ", infoplistname); } grub_file_close (infoplist); buf[infoplistsize] = 0; buf += infoplistsize + 1; } grub_errno = GRUB_ERR_NONE; exthead->nameaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) + grub_xnu_heap_will_be_at; exthead->namesize = namelen + 1; grub_memcpy (buf, name, namelen); buf[namelen] = 0; buf += namelen + 1; /* Announce to kernel */ return grub_xnu_register_memory ("Driver-", &driversnum, exthead, neededspace); }
/* Load extension DIRNAME. (extensions are directories in xnu) */ grub_err_t grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, int maxrecursion) { grub_device_t dev; char *newdirname; char *newpath; char *device_name; grub_fs_t fs; const char *path; char *binsuffix; grub_file_t binfile; newdirname = grub_malloc (grub_strlen (dirname) + 20); if (! newdirname) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate buffer"); grub_strcpy (newdirname, dirname); newdirname[grub_strlen (dirname)] = '/'; newdirname[grub_strlen (dirname) + 1] = 0; device_name = grub_file_get_device_name (dirname); dev = grub_device_open (device_name); if (dev) { struct grub_xnu_load_kext_from_dir_closure c; fs = grub_fs_probe (dev); path = grub_strchr (dirname, ')'); if (! path) path = dirname; else path++; newpath = grub_strchr (newdirname, ')'); if (! newpath) newpath = newdirname; else newpath++; c.dirname = dirname; c.osbundlerequired = osbundlerequired; c.maxrecursion = maxrecursion; c.usemacos = 0; c.plistname = 0; c.newdirname = newdirname; /* Look at the directory. */ if (fs) (fs->dir) (dev, path, grub_xnu_load_kext_from_dir_hook, &c); if (c.plistname && grub_xnu_check_os_bundle_required (c.plistname, osbundlerequired, &binsuffix)) { if (binsuffix) { /* Open the binary. */ char *binname = grub_malloc (grub_strlen (dirname) + grub_strlen (binsuffix) + sizeof ("/MacOS/")); grub_strcpy (binname, dirname); if (c.usemacos) grub_strcpy (binname + grub_strlen (binname), "/MacOS/"); else grub_strcpy (binname + grub_strlen (binname), "/"); grub_strcpy (binname + grub_strlen (binname), binsuffix); grub_dprintf ("xnu", "%s:%s\n", c.plistname, binname); binfile = grub_gzfile_open (binname, 1); if (! binfile) grub_errno = GRUB_ERR_NONE; /* Load the extension. */ grub_xnu_load_driver (c.plistname, binfile); grub_free (binname); grub_free (binsuffix); } else { grub_dprintf ("xnu", "%s:0\n", c.plistname); grub_xnu_load_driver (c.plistname, 0); } } grub_free (c.plistname); grub_device_close (dev); } grub_free (device_name); return GRUB_ERR_NONE; }
static grub_err_t grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { grub_ssize_t rd1, rd2; grub_off_t pos; grub_file_t file1 = 0; grub_file_t file2 = 0; char *buf1 = 0; char *buf2 = 0; if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments required"); grub_printf ("Compare file `%s' with `%s':\n", args[0], args[1]); file1 = grub_gzfile_open (args[0], 1); file2 = grub_gzfile_open (args[1], 1); if (! file1 || ! file2) goto cleanup; if (grub_file_size (file1) != grub_file_size (file2)) grub_printf ("Files differ in size: %llu [%s], %llu [%s]\n", (unsigned long long) grub_file_size (file1), args[0], (unsigned long long) grub_file_size (file2), args[1]); else { pos = 0; buf1 = grub_malloc (BUFFER_SIZE); buf2 = grub_malloc (BUFFER_SIZE); if (! buf1 || ! buf2) goto cleanup; do { int i; rd1 = grub_file_read (file1, buf1, BUFFER_SIZE); rd2 = grub_file_read (file2, buf2, BUFFER_SIZE); if (rd1 != rd2) goto cleanup; for (i = 0; i < rd2; i++) { if (buf1[i] != buf2[i]) { grub_printf ("Files differ at the offset %llu: 0x%x [%s], 0x%x [%s]\n", (unsigned long long) (i + pos), buf1[i], args[0], buf2[i], args[1]); goto cleanup; } } pos += BUFFER_SIZE; } while (rd2); grub_printf ("The files are identical.\n"); } cleanup: if (buf1) grub_free (buf1); if (buf2) grub_free (buf2); if (file1) grub_file_close (file1); if (file2) grub_file_close (file2); return grub_errno; }
void grub_module2 (int argc, char *argv[]) { grub_file_t file; grub_addr_t modaddr = 0; grub_ssize_t modsize = 0; grub_err_t err; if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); return; } if (argc == 1) { grub_error (GRUB_ERR_BAD_ARGUMENT, "No module type specified"); return; } if (entry == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the multiboot kernel first"); return; } /* Load module data. */ file = grub_gzfile_open (argv[0], 1); if (! file) goto out; modsize = grub_file_size (file); err = grub_mb2_arch_module_alloc (modsize, &modaddr); if (err) goto out; grub_dprintf ("loader", "Loading module at 0x%x - 0x%x\n", modaddr, modaddr + modsize); if (grub_file_read (file, (char *) modaddr, modsize) != modsize) { grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); goto out; } /* Create the module tag. */ err = grub_mb2_tag_module_create (modaddr, modsize, argv[1], MULTIBOOT2_TAG_MODULE, argc-2, &argv[2]); if (err) goto out; out: grub_error_push (); if (file) grub_file_close (file); if (modaddr) grub_mb2_arch_module_free (modaddr, modsize); grub_error_pop (); }
void grub_multiboot2 (int argc, char *argv[]) { char *buffer; grub_file_t file = 0; grub_elf_t elf = 0; struct multiboot_header *header = 0; char *p; grub_ssize_t len; grub_err_t err; int header_found = 0; grub_loader_unset (); if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified"); goto fail; } file = grub_gzfile_open (argv[0], 1); if (! file) { grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file"); goto fail; } buffer = grub_malloc (MULTIBOOT2_HEADER_SEARCH); if (! buffer) return; len = grub_file_read (file, buffer, MULTIBOOT2_HEADER_SEARCH); if (len < 32) { grub_error (GRUB_ERR_BAD_OS, "File too small"); goto fail; } /* Look for the multiboot header in the buffer. The header should be at least 8 bytes and aligned on a 8-byte boundary. */ for (p = buffer; p <= buffer + len - 8; p += 8) { header = (struct multiboot_header *) p; if (header->magic == MULTIBOOT2_HEADER_MAGIC) { header_found = 1; break; } } if (! header_found) grub_dprintf ("loader", "No multiboot 2 header found.\n"); /* Create the basic tags. */ grub_dprintf ("loader", "Creating multiboot 2 tags\n"); grub_mb2_tags_create (); /* Load the kernel and create its tag. */ elf = grub_elf_file (file); if (elf) { grub_dprintf ("loader", "Loading ELF multiboot 2 file.\n"); err = grub_mb2_load_elf (elf, argc-1, &argv[1]); grub_elf_close (elf); } else { grub_errno = 0; grub_dprintf ("loader", "Loading non-ELF multiboot 2 file.\n"); if (header) err = grub_mb2_load_other (file, header); else err = grub_error (GRUB_ERR_BAD_OS, "Need multiboot 2 header to load non-ELF files."); grub_file_close (file); } grub_free (buffer); if (err) goto fail; /* Good to go. */ grub_loader_set (grub_mb2_boot, grub_mb2_unload, 1); return; fail: grub_mb2_tags_free (); grub_dl_unref (my_mod); }