From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kasper Brink Subject: pv-grub Solaris support Date: Wed, 12 Oct 2011 22:40:11 +0200 Message-ID: <20111012204011.GA7518@lilo2.science.ru.nl> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="zhXaljGHf11kAtnf" Return-path: Content-Disposition: inline List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: xen-devel@lists.xensource.com List-Id: xen-devel@lists.xenproject.org --zhXaljGHf11kAtnf Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hello all, I've patched pv-grub to allow it to boot a Solaris PV domU using an unmodified menu.lst. The attached patch has been tested with various Solaris versions (Solaris 11 Express, OpenIndiana 151a, OpenSolaris 134, Nexenta Core 3.0.1; all 64-bit). I appreciate your feedback. The patch consists mainly of Oracle's grub modifications, which add ZFS support and Solaris-specific builtins (findroot, bootfs, kernel$, and module$). I took the relevant code from the "Oracle Solaris 11 Express 2010.11 GPL Source, Part 2" package, downloaded from: http://dlc.sun.com/opensourcecode/solaris/sol-11-exp-201011-GPLSource_2.zip The kernel$ and module$ builtins were modified to boot Xen PV Solaris kernels. The patch is against current xen-unstable. I built and tested pv-grub under Xen version 4.0.1 (Debian 4.0.1-2) amd64, with a Linux 2.6.32-5-xen-amd64 (Debian Squeeze) dom0. The location of menu.lst in the domU was specified with the "extra" variable (e.g. extra="(hd0,0,a)/boot/grub/menu.lst"). Note: I had to create a symlink "xen/include/xen/libelf -> ." (not in the patch) to build stubdom/libxc-x86_64 succesfully. Is this a bug, or is there something wrong in my setup? If you think this code is useful for other users, I'd be happy to see it included in the Xen repository. Please let me know if there's anything that needs to be changed. Best, Kasper --zhXaljGHf11kAtnf Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="pv-grub_solaris.patch" diff -r 4b0907c6a08c stubdom/grub.patches/60zfs_solaris.diff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubdom/grub.patches/60zfs_solaris.diff Wed Oct 12 20:06:15 2011 +0200 @@ -0,0 +1,4793 @@ +This patch adds ZFS support, and the Solaris-specific builtins findroot, bootfs, +kernel$, and module$, to pv-grub. + +It includes the relevant parts of Oracle's changes to grub-0.97, which were +taken from the "osnet/src/grub-0.97" directory in the "Oracle Solaris 11 +Express 2010.11 GPL Source, Part 2" archive, downloaded from: + http://dlc.sun.com/opensourcecode/solaris/sol-11-exp-201011-GPLSource_2.zip + +The kernel$ and module$ builtins were modified to boot Xen PV Solaris kernels. + + 2011-10-12 Kasper Brink + + +diff -urN grub.patch50/AUTHORS grub.zfs_solaris/AUTHORS +--- grub.patch50/AUTHORS 2011-10-12 19:58:28.795922895 +0200 ++++ grub.zfs_solaris/AUTHORS 2011-10-12 19:58:28.951921541 +0200 +@@ -1,7 +1,16 @@ ++ ++ZFS support added by Sun Microsystems. ++Copyright 2007 Sun Microsystems, Inc. All rights reserved. ++Use is subject to license terms. ++ + VaX#n8 (real name unknown) wrote shared_src/fsys_ext2fs.c. + + Heiko Schroeder rewrote shared_src/stage1.S to be more readable. + ++Solaris VTOC and UFS support added by Sun Microsystems. ++Copyright 2005 Sun Microsystems, Inc. All rights reserved. ++Use is subject to license terms. ++ + The following authors assigned copyright on their work to the Free + Software Foundation: + +diff -urN grub.patch50/stage2/builtins.c grub.zfs_solaris/stage2/builtins.c +--- grub.patch50/stage2/builtins.c 2011-10-12 19:58:28.871922077 +0200 ++++ grub.zfs_solaris/stage2/builtins.c 2011-10-12 19:58:29.027921196 +0200 +@@ -109,6 +109,12 @@ + fallback_entryno = -1; + fallback_entries[0] = -1; + grub_timeout = -1; ++ current_rootpool[0] = '\0'; ++ current_bootfs[0] = '\0'; ++ current_bootpath[0] = '\0'; ++ current_bootfs_obj = 0; ++ current_devid[0] = '\0'; ++ is_zfs_mount = 0; + } + + /* Check a password for correctness. Returns 0 if password was +@@ -1467,16 +1473,56 @@ + }; + + +-/* find */ +-/* Search for the filename ARG in all of partitions. */ ++ ++void ++set_root (char *root, unsigned long drive, unsigned long part) ++{ ++ int bsd_part = (part >> 8) & 0xFF; ++ int pc_slice = part >> 16; ++ ++ if (bsd_part == 0xFF) { ++ grub_sprintf (root, "(hd%d,%d)\n", drive - 0x80, pc_slice); ++ } else { ++ grub_sprintf (root, "(hd%d,%d,%c)\n", ++ drive - 0x80, pc_slice, bsd_part + 'a'); ++ } ++} ++ + static int +-find_func (char *arg, int flags) ++find_common (char *arg, char *root, int for_root, int flags) + { +- char *filename = arg; ++ char *filename = NULL; ++ static char argpart[32]; ++ static char device[32]; ++ char *tmp_argpart = NULL; + unsigned long drive; + unsigned long tmp_drive = saved_drive; + unsigned long tmp_partition = saved_partition; + int got_file = 0; ++ static char bootsign[BOOTSIGN_LEN]; ++ ++ /* ++ * If argument has partition information (findroot command only), then ++ * it can't be a floppy ++ */ ++ if (for_root && arg[0] == '(') { ++ tmp_argpart = grub_strchr(arg + 1, ','); ++ if (tmp_argpart == NULL) ++ goto out; ++ grub_strcpy(argpart, tmp_argpart); ++ *tmp_argpart = '\0'; ++ arg++; ++ grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg); ++ filename = bootsign; ++ goto harddisk; ++ } else if (for_root && !grub_strchr(arg, '/')) { ++ /* Boot signature without partition/slice information */ ++ grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg); ++ filename = bootsign; ++ } else { ++ /* plain vanilla find cmd */ ++ filename = arg; ++ } + + /* Floppies. */ + for (drive = 0; drive < 8; drive++) +@@ -1491,14 +1537,19 @@ + if (grub_open (filename)) + { + grub_close (); +- grub_printf (" (fd%d)\n", drive); + got_file = 1; ++ if (for_root) { ++ grub_sprintf(root, "(fd%d)", drive); ++ goto out; ++ } else ++ grub_printf (" (fd%d)\n", drive); + } + } + + errnum = ERR_NONE; + } + ++harddisk: + /* Hard disks. */ + for (drive = 0x80; drive < 0x88; drive++) + { +@@ -1507,6 +1558,30 @@ + int type, entry; + char buf[SECTOR_SIZE]; + ++ if (for_root && tmp_argpart) { ++ grub_sprintf(device, "(hd%d%s", drive - 0x80, argpart); ++ set_device(device); ++ errnum = ERR_NONE; ++ part = current_partition; ++ if (open_device ()) { ++ saved_drive = current_drive; ++ saved_partition = current_partition; ++ errnum = ERR_NONE; ++ if (grub_open (filename)) { ++ grub_close (); ++ got_file = 1; ++ if (is_zfs_mount == 0) { ++ set_root(root, current_drive, current_partition); ++ goto out; ++ } else { ++ best_drive = current_drive; ++ best_part = current_partition; ++ } ++ } ++ } ++ errnum = ERR_NONE; ++ continue; ++ } + current_drive = drive; + while (next_partition (drive, 0xFFFFFF, &part, &type, + &start, &len, &offset, &entry, +@@ -1523,19 +1598,22 @@ + saved_partition = current_partition; + if (grub_open (filename)) + { +- int bsd_part = (part >> 8) & 0xFF; +- int pc_slice = part >> 16; +- +- grub_close (); +- +- if (bsd_part == 0xFF) +- grub_printf (" (hd%d,%d)\n", +- drive - 0x80, pc_slice); +- else +- grub_printf (" (hd%d,%d,%c)\n", +- drive - 0x80, pc_slice, bsd_part + 'a'); ++ char tmproot[32]; + ++ grub_close (); + got_file = 1; ++ set_root(tmproot, drive, part); ++ if (for_root) { ++ grub_memcpy(root, tmproot, sizeof(tmproot)); ++ if (is_zfs_mount == 0) { ++ goto out; ++ } else { ++ best_drive = current_drive; ++ best_part = current_partition; ++ } ++ } else { ++ grub_printf("%s", tmproot); ++ } + } + } + } +@@ -1549,8 +1627,16 @@ + errnum = ERR_NONE; + } + +- saved_drive = tmp_drive; +- saved_partition = tmp_partition; ++out: ++ if (is_zfs_mount && for_root) { ++ set_root(root, best_drive, best_part); ++ buf_drive = -1; ++ } else { ++ saved_drive = tmp_drive; ++ saved_partition = tmp_partition; ++ } ++ if (tmp_argpart) ++ *tmp_argpart = ','; + + if (got_file) + { +@@ -1562,6 +1648,14 @@ + return 1; + } + ++/* find */ ++/* Search for the filename ARG in all of partitions. */ ++static int ++find_func (char *arg, int flags) ++{ ++ return (find_common(arg, NULL, 0, flags)); ++} ++ + static struct builtin builtin_find = + { + "find", +@@ -2619,6 +2713,117 @@ + + + ++/* ++ * To boot from a ZFS root filesystem, the kernel$ or module$ commands ++ * must include "-B $ZFS-BOOTFS" to expand to the zfs-bootfs, bootpath, ++ * and diskdevid boot property values for passing to the kernel: ++ * ++ * e.g. ++ * kernel$ /platform/i86pc/kernel/$ISADIR/unix -B $ZFS-BOOTFS,console=ttya ++ * ++ * $ZFS-BOOTFS is expanded to ++ * ++ * zfs-bootfs=, ++ * bootpath=, ++ * diskdevid= ++ * ++ * if both bootpath and diskdevid can be found. ++ * e.g ++ * zfs-bootfs=rpool/85, ++ * bootpath="/pci@0,0/pci1022,7450@a/pci17c2,10@4/sd@0,0:a", ++ * diskdevid="id1,sd@SSEAGATE_ST336607LC______3JA0LNHE0000741326W6/a" ++ */ ++static int ++expand_dollar_bootfs(char *in, char *out) ++{ ++ char *token, *tmpout = out; ++ int outlen, blen; ++ int postcomma = 0; ++ ++ /* no op if this is not zfs */ ++ if (is_zfs_mount == 0) ++ return (0); ++ ++ if (current_bootpath[0] == '\0' && current_devid[0] == '\0') { ++ errnum = ERR_NO_BOOTPATH; ++ return (1); ++ } ++ ++ outlen = strlen(in); ++ blen = current_bootfs_obj == 0 ? strlen(current_rootpool) : ++ strlen(current_rootpool) + 11; ++ ++ out[0] = '\0'; ++ while (token = strstr(in, "$ZFS-BOOTFS")) { ++ ++ if ((outlen += blen) >= MAX_CMDLINE) { ++ errnum = ERR_WONT_FIT; ++ return (1); ++ } ++ ++ token[0] = '\0'; ++ grub_sprintf(tmpout, "%s", in); ++ token[0] = '$'; ++ in = token + 11; /* skip over $ZFS-BOOTFS */ ++ tmpout = out + strlen(out); ++ ++ /* Note: %u only fits 32 bit integer; */ ++ if (current_bootfs_obj > 0) ++ grub_sprintf(tmpout, "zfs-bootfs=%s/%u", ++ current_rootpool, current_bootfs_obj); ++ else ++ grub_sprintf(tmpout, "zfs-bootfs=%s", ++ current_rootpool); ++ tmpout = out + strlen(out); ++ } ++ ++ /* ++ * Check to see if 'zfs-bootfs' was explicitly specified on the command ++ * line so that we can insert the 'bootpath' property. ++ */ ++ if ((tmpout == out) && (token = strstr(in, "zfs-bootfs")) != NULL) { ++ token[0] = '\0'; ++ grub_strcpy(tmpout, in); ++ token[0] = 'z'; ++ in = token; ++ ++ tmpout = out + strlen(out); ++ postcomma = 1; ++ } ++ ++ /* ++ * Set the 'bootpath' property if a ZFS dataset was specified, either ++ * through '$ZFS-BOOTFS' or an explicit 'zfs-bootfs' setting. ++ */ ++ if (tmpout != out) { ++ if (current_bootpath[0] != '\0') { ++ if ((outlen += 12 + strlen(current_bootpath)) ++ >= MAX_CMDLINE) { ++ errnum = ERR_WONT_FIT; ++ return (1); ++ } ++ grub_sprintf(tmpout, ++ postcomma ? "bootpath=\"%s\"," : ",bootpath=\"%s\"", ++ current_bootpath); ++ tmpout = out + strlen(out); ++ } ++ ++ if (current_devid[0] != '\0') { ++ if ((outlen += 13 + strlen(current_devid)) ++ >= MAX_CMDLINE) { ++ errnum = ERR_WONT_FIT; ++ return (1); ++ } ++ grub_sprintf(tmpout, ++ postcomma ? "diskdevid=\"%s\"," : ",diskdevid=\"%s\"", ++ current_devid); ++ } ++ } ++ ++ strncat(out, in, MAX_CMDLINE); ++ return (0); ++} ++ + /* kernel */ + static int + kernel_func (char *arg, int flags) +@@ -2707,6 +2912,141 @@ + " Linux's mem option automatically." + }; + ++int ++isamd64() ++{ ++ static int ret = 0; ++ ++#ifdef __x86_64__ ++ ret = 1; ++#endif ++ ++ return (ret); ++} ++ ++static void ++expand_arch (char *arg, char *newarg) ++{ ++ char *index; ++ ++ newarg[0] = '\0'; ++ ++ while ((index = strstr(arg, "$ISADIR")) != NULL) { ++ ++ index[0] = '\0'; ++ strncat(newarg, arg, MAX_CMDLINE); ++ index[0] = '$'; ++ ++ if (isamd64()) ++ strncat(newarg, "amd64", MAX_CMDLINE); ++ ++ arg = index + 7; ++ } ++ ++ strncat(newarg, arg, MAX_CMDLINE); ++ return; ++} ++ ++static int ++substitute_platform_i86xpv (char *arg, char *newarg) ++{ ++ char *index; ++ ++ newarg[0] = '\0'; ++ ++ while ((index = strstr(arg, "i86pc")) != NULL) { ++ ++ index[0] = '\0'; ++ if (!strncat(newarg, arg, MAX_CMDLINE) ++ || !strncat(newarg, "i86xpv", MAX_CMDLINE)) { ++ errnum = ERR_WONT_FIT; ++ return (1); ++ } ++ index[0] = 'i'; ++ ++ arg = index + 5; /* length of "i86pc" */ ++ } ++ ++ if (!strncat(newarg, arg, MAX_CMDLINE)) { ++ errnum = ERR_WONT_FIT; ++ return (1); ++ } ++ ++ return (0); ++} ++ ++/* kernel$ */ ++static int ++kernel_dollar_func (char *arg, int flags) ++{ ++ char newarg[MAX_CMDLINE]; /* everything boils down to MAX_CMDLINE */ ++#ifdef __MINIOS__ ++ char tmparg[MAX_CMDLINE]; ++#endif ++ ++ grub_printf("loading '%s' ...\n", arg); ++ expand_arch(arg, newarg); ++ ++#ifdef __MINIOS__ ++ /* replace "i86pc" by "i86xpv" in the kernel filename, ++ to enable pv-grub to use an unmodified menu.lst */ ++ if (substitute_platform_i86xpv(newarg,tmparg)) ++ return (1); ++ ++ /* on ZFS, grub_open the kernel to set the value of current_bootfs_obj */ ++ grub_strcpy(newarg,tmparg); ++ nul_terminate(newarg); ++ if (is_zfs_mount) { ++ if (!grub_open(newarg)) ++ return (1); ++ grub_close(); ++ } ++ ++ /* the kernel filename is duplicated as the first argument to the kernel */ ++ if (!strncat(newarg, " ", MAX_CMDLINE) ++ || !strncat(newarg, tmparg, MAX_CMDLINE)) { ++ errnum = ERR_WONT_FIT; ++ return (1); ++ } ++ ++ grub_strcpy(tmparg,newarg); ++ if (expand_dollar_bootfs(tmparg, newarg)) { ++ grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n", ++ current_bootfs); ++ return (1); ++ } ++ ++ if (kernel_func(newarg, flags)) ++ return (1); ++ ++ grub_printf("'%s' is loaded\n", newarg); ++#else /* ! __MINIOS__ */ ++ if (kernel_func(newarg, flags)) ++ return (1); ++ ++ mb_cmdline = (char *)MB_CMDLINE_BUF; ++ if (expand_dollar_bootfs(newarg, mb_cmdline)) { ++ grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n", ++ current_bootfs); ++ return (1); ++ } ++ ++ grub_printf("'%s' is loaded\n", mb_cmdline); ++ mb_cmdline += grub_strlen(mb_cmdline) + 1; ++#endif /* ! __MINIOS__ */ ++ ++ return (0); ++} ++ ++static struct builtin builtin_kernel_dollar = ++{ ++ "kernel$", ++ kernel_dollar_func, ++ BUILTIN_CMDLINE | BUILTIN_HELP_LIST, ++ "kernel$ [--no-mem-option] [--type=TYPE] FILE [ARG ...]", ++ " Just like kernel, but with $ISADIR expansion." ++}; ++ + + /* lock */ + static int +@@ -2922,6 +3262,50 @@ + " the `kernel' command." + }; + ++/* module$ */ ++static int ++module_dollar_func (char *arg, int flags) ++{ ++ char newarg[MAX_CMDLINE]; /* everything boils down to MAX_CMDLINE */ ++ char *cmdline_sav; ++ ++ grub_printf("loading '%s' ...\n", arg); ++ expand_arch(arg, newarg); ++ ++/* Xen PV Solaris kernels ("i86xpv") are not Multiboot-compliant, and expect ++ to receive the boot archive as a Linux-style initial ramdisk. */ ++#ifdef __MINIOS__ ++ if (initrd_func(newarg, flags)) ++ return (1); ++ ++ grub_printf("'%s' is loaded\n", newarg); ++#else /* ! __MINIOS__ */ ++ cmdline_sav = (char *)mb_cmdline; ++ if (module_func(newarg, flags)) ++ return (1); ++ ++ if (expand_dollar_bootfs(newarg, cmdline_sav)) { ++ grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n", ++ current_bootfs); ++ return (1); ++ } ++ ++ grub_printf("'%s' is loaded\n", (char *)cmdline_sav); ++ mb_cmdline += grub_strlen(cmdline_sav) + 1; ++#endif /* ! __MINIOS__ */ ++ ++ return (0); ++} ++ ++static struct builtin builtin_module_dollar = ++{ ++ "module$", ++ module_dollar_func, ++ BUILTIN_CMDLINE | BUILTIN_HELP_LIST, ++ "module FILE [ARG ...]", ++ " Just like module, but with $ISADIR expansion." ++}; ++ + + /* modulenounzip */ + static int +@@ -3469,6 +3853,7 @@ + static int + root_func (char *arg, int flags) + { ++ is_zfs_mount = 0; + return real_root_func (arg, 1); + } + +@@ -3491,6 +3876,101 @@ + }; + + ++/* findroot */ ++int ++findroot_func (char *arg, int flags) ++{ ++ int ret; ++ char root[32]; ++ ++ if (grub_strlen(arg) >= BOOTSIGN_ARGLEN) { ++ errnum = ERR_BAD_ARGUMENT; ++ return 1; ++ } ++ ++ if (arg[0] == '\0') { ++ errnum = ERR_BAD_ARGUMENT; ++ return 1; ++ } ++ ++ find_best_root = 1; ++ best_drive = 0; ++ best_part = 0; ++ ret = find_common(arg, root, 1, flags); ++ if (ret != 0) ++ return (ret); ++ find_best_root = 0; ++ ++ return real_root_func (root, 1); ++} ++ ++static struct builtin builtin_findroot = ++{ ++ "findroot", ++ findroot_func, ++ BUILTIN_CMDLINE | BUILTIN_HELP_LIST, ++ "findroot ", ++ "Searches across all partitions for the file name SIGNATURE." ++ " GRUB looks only in the directory /boot/grub/bootsign for the" ++ " filename and it stops as soon as it finds the first instance of" ++ " the file - so to be useful the name of the signature file must be" ++ " unique across all partitions. Once the signature file is found," ++ " GRUB invokes the \"root\" command on that partition." ++ " An optional partition and slice may be specified to optimize the search." ++}; ++ ++ ++/* ++ * COMMAND to override the default root filesystem for ZFS ++ * bootfs pool/fs ++ */ ++static int ++bootfs_func (char *arg, int flags) ++{ ++ int hdbias = 0; ++ char *biasptr; ++ char *next; ++ ++ if (! *arg) { ++ if (current_bootfs[0] != '\0') ++ grub_printf ("The zfs boot filesystem is set to '%s'.\n", ++ current_bootfs); ++ else if (current_rootpool[0] != 0 && current_bootfs_obj != 0) ++ grub_printf("The zfs boot filesystem is .", ++ current_rootpool, current_bootfs_obj); ++ else ++ grub_printf ("The zfs boot filesystem will be derived from " ++ "the default bootfs pool property.\n"); ++ ++ return (1); ++ } ++ ++ /* Verify the zfs filesystem name */ ++ if (arg[0] == '/' || arg[0] == '\0') { ++ errnum = ERR_BAD_ARGUMENT; ++ return 0; ++ } ++ if (current_rootpool[0] != 0 && grub_strncmp(arg, ++ current_rootpool, strlen(current_rootpool))) { ++ errnum = ERR_BAD_ARGUMENT; ++ return 0; ++ } ++ ++ grub_memmove(current_bootfs, arg, MAXNAMELEN); ++ ++ return (1); ++} ++ ++static struct builtin builtin_bootfs = ++{ ++ "bootfs", ++ bootfs_func, ++ BUILTIN_CMDLINE | BUILTIN_HELP_LIST, ++ "bootfs [ZFSBOOTFS]", ++ "Set the current zfs boot filesystem to ZFSBOOTFS (rootpool/rootfs)." ++}; ++ ++ + /* rootnoverify */ + static int + rootnoverify_func (char *arg, int flags) +@@ -3630,6 +4110,11 @@ + int saved_offsets[2]; + int saved_lengths[2]; + ++ /* not supported for zfs root */ ++ if (is_zfs_mount == 1) { ++ return (0); /* no-op */ ++ } ++ + /* Save sector information about at most two sectors. */ + auto void disk_read_savesect_func (int sector, int offset, int length); + void disk_read_savesect_func (int sector, int offset, int length) +@@ -5213,6 +5698,7 @@ + #endif + &builtin_blocklist, + &builtin_boot, ++ &builtin_bootfs, + #ifdef SUPPORT_NETBOOT + &builtin_bootp, + #endif /* SUPPORT_NETBOOT */ +@@ -5241,6 +5727,7 @@ + &builtin_embed, + &builtin_fallback, + &builtin_find, ++ &builtin_findroot, + #ifdef SUPPORT_GRAPHICS + &builtin_foreground, + #endif +@@ -5258,6 +5745,7 @@ + &builtin_install, + &builtin_ioprobe, + &builtin_kernel, ++ &builtin_kernel_dollar, + &builtin_lock, + &builtin_makeactive, + &builtin_map, +@@ -5265,6 +5753,7 @@ + &builtin_md5crypt, + #endif /* USE_MD5_PASSWORDS */ + &builtin_module, ++ &builtin_module_dollar, + &builtin_modulenounzip, + &builtin_pager, + &builtin_partnew, +diff -urN grub.patch50/stage2/char_io.c grub.zfs_solaris/stage2/char_io.c +--- grub.patch50/stage2/char_io.c 2011-10-12 19:58:28.871922077 +0200 ++++ grub.zfs_solaris/stage2/char_io.c 2011-10-12 19:58:29.027921196 +0200 +@@ -17,6 +17,10 @@ + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ ++/* ++ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ + + #include + #include +@@ -217,7 +221,7 @@ + } + } + +-#ifndef STAGE1_5 ++#if !defined(STAGE1_5) || defined(FSYS_ZFS) + int + grub_sprintf (char *buffer, const char *format, ...) + { +@@ -261,8 +265,10 @@ + *bp = 0; + return bp - buffer; + } ++#endif /* !defined(STAGE1_5) || defined(FSYS_ZFS) */ + + ++#ifndef STAGE1_5 + void + init_page (void) + { +@@ -1013,7 +1019,10 @@ + a static library supporting minimal standard C functions and link + each image with the library. Complicated things should be left to + computer, definitely. -okuji */ +-#if !defined(STAGE1_5) || defined(FSYS_VSTAFS) ++ ++/* Make some grub_str* routines available to ZFS plug-in as well */ ++ ++#if !defined(STAGE1_5) || defined(FSYS_VSTAFS) || defined(FSYS_ZFS) + int + grub_strcmp (const char *s1, const char *s2) + { +@@ -1029,7 +1038,20 @@ + + return 0; + } +-#endif /* ! STAGE1_5 || FSYS_VSTAFS */ ++ ++int ++grub_strncmp(const char *s1, const char *s2, int n) ++{ ++ if (s1 == s2) ++ return (0); ++ n++; ++ while (--n != 0 && *s1 == *s2++) ++ if (*s1++ == '\0') ++ return (0); ++ return ((n == 0) ? 0 : *(unsigned char *)s1 - *(unsigned char *)--s2); ++} ++ ++#endif /* ! STAGE1_5 || FSYS_VSTAFS || defined(FSYS_ZFS) */ + + #ifndef STAGE1_5 + /* Wait for a keypress and return its code. */ +@@ -1195,7 +1217,9 @@ + *str = 0; + return ch; + } ++#endif + ++#if !defined(STAGE1_5) || defined(FSYS_ZFS) + char * + grub_strstr (const char *s1, const char *s2) + { +@@ -1228,6 +1252,16 @@ + + return len; + } ++#endif /* !defined(STAGE1_5) || defined(FSYS_ZFS) */ ++ ++#ifndef STAGE1_5 ++char * ++grub_strchr (char *str, char c) ++{ ++ for (; *str && (*str != c); str++); ++ ++ return (*str ? str : NULL); ++} + #endif /* ! STAGE1_5 */ + + int +diff -urN grub.patch50/stage2/common.c grub.zfs_solaris/stage2/common.c +--- grub.patch50/stage2/common.c 2011-10-12 19:58:28.871922077 +0200 ++++ grub.zfs_solaris/stage2/common.c 2011-10-12 19:58:29.027921196 +0200 +@@ -88,6 +88,10 @@ + [ERR_UNRECOGNIZED] = "Unrecognized command", + [ERR_WONT_FIT] = "Selected item cannot fit into memory", + [ERR_WRITE] = "Disk write error", ++ [ERR_FILESYSTEM_NOT_FOUND] = "File System not found", ++ /* this zfs file system is not found in the pool of the device */ ++ [ERR_NO_BOOTPATH] = "No valid boot path found in the zfs label. This may be caused by attempting to boot from an off-lined device.", ++ [ERR_NEWER_VERSION] = "Newer on-disk pool version", + }; + + +diff -urN grub.patch50/stage2/disk_io.c grub.zfs_solaris/stage2/disk_io.c +--- grub.patch50/stage2/disk_io.c 2011-10-12 19:58:28.875921314 +0200 ++++ grub.zfs_solaris/stage2/disk_io.c 2011-10-12 19:58:29.031921885 +0200 +@@ -75,6 +75,9 @@ + # ifdef FSYS_UFS2 + {"ufs2", ufs2_mount, ufs2_read, ufs2_dir, 0, ufs2_embed}, + # endif ++# ifdef FSYS_ZFS ++ {"zfs", zfs_mount, zfs_read, zfs_open, 0, zfs_embed}, ++# endif + # ifdef FSYS_ISO9660 + {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0}, + # endif +@@ -118,6 +121,17 @@ + + int current_slice; + ++/* ZFS root filesystem for booting */ ++char current_rootpool[MAXNAMELEN]; ++char current_bootfs[MAXNAMELEN]; ++unsigned long long current_bootfs_obj; ++char current_bootpath[MAXPATHLEN]; ++char current_devid[MAXPATHLEN]; ++int is_zfs_mount; ++unsigned long best_drive; ++unsigned long best_part; ++int find_best_root; ++ + /* disk buffer parameters */ + int buf_drive = -1; + int buf_track; +@@ -404,7 +418,7 @@ + || current_drive == cdrom_drive) + && (current_partition & 0xFF) == 0xFF + && ((current_partition & 0xFF00) == 0xFF00 +- || (current_partition & 0xFF00) < 0x800) ++ || (current_partition & 0xFF00) < 0x1000) + && ((current_partition >> 16) == 0xFF + || (current_drive & 0x80))) + return 1; +@@ -581,6 +595,7 @@ + { + /* Forward declarations. */ + auto int next_bsd_partition (void); ++ auto int next_solaris_partition(void); + auto int next_pc_slice (void); + + /* Get next BSD partition in current PC slice. */ +@@ -640,6 +655,56 @@ + return 0; + } + ++ /* Get next Solaris partition in current PC slice. */ ++ int next_solaris_partition (void) ++ { ++ static unsigned long pcs_start; ++ int i; ++ int sol_part_no = (*partition & 0xFF00) >> 8; ++ ++ /* If this is the first time... */ ++ if (sol_part_no == 0xFF) ++ { ++ /* Check if the Solaris label is within current PC slice. */ ++ if (*len < SOL_LABEL_LOC + 1) ++ { ++ errnum = ERR_BAD_PART_TABLE; ++ return 0; ++ } ++ ++ /* Read the Solaris label. */ ++ if (! rawread (drive, *start + SOL_LABEL_LOC, 0, SECTOR_SIZE, buf)) ++ return 0; ++ ++ /* Check if it is valid. */ ++ if (! SOL_LABEL_CHECK_MAG (buf)) ++ { ++ errnum = ERR_BAD_PART_TABLE; ++ return 0; ++ } ++ ++ sol_part_no = -1; ++ pcs_start = *start; /* save the start of pc slice */ ++ } ++ ++ /* Search next valid Solaris partition. */ ++ for (i = sol_part_no + 1; i < SOL_LABEL_NPARTS; i++) ++ { ++ if (SOL_PART_EXISTS (buf, i)) ++ { ++ /* SOL_PART_START is relative to fdisk partition */ ++ *start = SOL_PART_START (buf, i) + pcs_start; ++ *len = SOL_PART_LENGTH (buf, i); ++ *partition = (*partition & 0xFF00FF) | (i << 8); ++ ++ return 1; ++ } ++ } ++ ++ errnum = ERR_NO_PART; ++ return 0; ++ } ++ + /* Get next PC slice. Be careful of that this function may return + an empty PC slice (i.e. a partition whose type is zero) as well. */ + int next_pc_slice (void) +@@ -717,6 +782,14 @@ + return 0; + #endif + ++ /* check for Solaris partition */ ++ if (*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_SOLARIS (*type & 0xff)) ++ { ++ if (next_solaris_partition ()) ++ return 1; ++ errnum = ERR_NONE; ++ } ++ + /* If previous partition is a BSD partition or a PC slice which + contains BSD partitions... */ + if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff)) +@@ -830,7 +903,8 @@ + grub_printf (" Partition num: %d, ", + current_partition >> 16); + +- if (! IS_PC_SLICE_TYPE_BSD (current_slice)) ++ if (! IS_PC_SLICE_TYPE_BSD (current_slice) && ++ ! IS_PC_SLICE_TYPE_SOLARIS (current_slice)) + check_and_print_mount (); + else + { +@@ -844,17 +918,17 @@ + + if (! got_part) + { +- grub_printf ("[BSD sub-partitions immediately follow]\n"); ++ grub_printf ("[BSD/SOLARIS sub-partitions immediately follow]\n"); + got_part = 1; + } + +- grub_printf (" BSD Partition num: \'%c\', ", ++ grub_printf (" BSD/SOLARIS Partition num: \'%c\', ", + bsd_part + 'a'); + check_and_print_mount (); + } + + if (! got_part) +- grub_printf (" No BSD sub-partition found, partition type 0x%x\n", ++ grub_printf (" No BSD/SOLARIS sub-partition found, partition type 0x%x\n", + saved_slice); + + if (errnum) +@@ -880,7 +954,8 @@ + pc_slice, bsd_part + 'a'); + print_a_completion (str); + } +- else if (! IS_PC_SLICE_TYPE_BSD (current_slice)) ++ else if (! IS_PC_SLICE_TYPE_BSD (current_slice) && ++ ! IS_PC_SLICE_TYPE_SOLARIS (current_slice)) + { + char str[8]; + +@@ -1038,7 +1113,7 @@ + } + else if (*device == ',') + { +- /* Either an absolute PC or BSD partition. */ ++ /* Either an absolute PC, BSD, or Solaris partition. */ + disk_choice = 0; + part_choice ++; + device++; +@@ -1061,13 +1136,13 @@ + if (*device == ',') + device++; + +- if (*device >= 'a' && *device <= 'h') ++ if (*device >= 'a' && *device <= 'p') + { + current_partition = (((*(device++) - 'a') << 8) + | (current_partition & 0xFF00FF)); + } + } +- else if (*device >= 'a' && *device <= 'h') ++ else if (*device >= 'a' && *device <= 'p') + { + part_choice ++; + current_partition = ((*(device++) - 'a') << 8) | 0xFF00FF; +diff -urN grub.patch50/stage2/filesys.h grub.zfs_solaris/stage2/filesys.h +--- grub.patch50/stage2/filesys.h 2011-10-12 19:58:28.875921314 +0200 ++++ grub.zfs_solaris/stage2/filesys.h 2011-10-12 19:58:29.031921885 +0200 +@@ -40,6 +40,16 @@ + #define FSYS_UFS2_NUM 0 + #endif + ++#ifdef FSYS_ZFS ++#define FSYS_ZFS_NUM 1 ++int zfs_mount (void); ++int zfs_read (char *buf, int len); ++int zfs_open (char *dirname); ++int zfs_embed (int *start_sector, int needed_sectors); ++#else ++#define FSYS_ZFS_NUM 0 ++#endif ++ + #ifdef FSYS_FAT + #define FSYS_FAT_NUM 1 + int fat_mount (void); +@@ -128,7 +138,7 @@ + #define NUM_FSYS \ + (FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM \ + + FSYS_REISERFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM + FSYS_XFS_NUM \ +- + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM) ++ + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM + FSYS_ZFS_NUM) + #endif + + /* defines for the block filesystem info area */ +diff -urN grub.patch50/stage2/fsys_zfs.c grub.zfs_solaris/stage2/fsys_zfs.c +--- grub.patch50/stage2/fsys_zfs.c 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/fsys_zfs.c 2011-10-12 19:58:29.035921285 +0200 +@@ -0,0 +1,1545 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. ++ */ ++ ++/* ++ * The zfs plug-in routines for GRUB are: ++ * ++ * zfs_mount() - locates a valid uberblock of the root pool and reads ++ * in its MOS at the memory address MOS. ++ * ++ * zfs_open() - locates a plain file object by following the MOS ++ * and places its dnode at the memory address DNODE. ++ * ++ * zfs_read() - read in the data blocks pointed by the DNODE. ++ * ++ * ZFS_SCRATCH is used as a working area. ++ * ++ * (memory addr) MOS DNODE ZFS_SCRATCH ++ * | | | ++ * +-------V---------V----------V---------------+ ++ * memory | | dnode | dnode | scratch | ++ * | | 512B | 512B | area | ++ * +--------------------------------------------+ ++ */ ++ ++#ifdef FSYS_ZFS ++ ++#include "shared.h" ++#include "filesys.h" ++#include "fsys_zfs.h" ++ ++/* cache for a file block of the currently zfs_open()-ed file */ ++static void *file_buf = NULL; ++static uint64_t file_start = 0; ++static uint64_t file_end = 0; ++ ++/* cache for a dnode block */ ++static dnode_phys_t *dnode_buf = NULL; ++static dnode_phys_t *dnode_mdn = NULL; ++static uint64_t dnode_start = 0; ++static uint64_t dnode_end = 0; ++ ++static uint64_t pool_guid = 0; ++static uberblock_t current_uberblock; ++static char *stackbase; ++ ++decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = ++{ ++ {"inherit", 0}, /* ZIO_COMPRESS_INHERIT */ ++ {"on", lzjb_decompress}, /* ZIO_COMPRESS_ON */ ++ {"off", 0}, /* ZIO_COMPRESS_OFF */ ++ {"lzjb", lzjb_decompress}, /* ZIO_COMPRESS_LZJB */ ++ {"empty", 0} /* ZIO_COMPRESS_EMPTY */ ++}; ++ ++static int zio_read_data(blkptr_t *bp, void *buf, char *stack); ++ ++/* ++ * Our own version of bcmp(). ++ */ ++static int ++zfs_bcmp(const void *s1, const void *s2, size_t n) ++{ ++ const uchar_t *ps1 = s1; ++ const uchar_t *ps2 = s2; ++ ++ if (s1 != s2 && n != 0) { ++ do { ++ if (*ps1++ != *ps2++) ++ return (1); ++ } while (--n != 0); ++ } ++ ++ return (0); ++} ++ ++/* ++ * Our own version of log2(). Same thing as highbit()-1. ++ */ ++static int ++zfs_log2(uint64_t num) ++{ ++ int i = 0; ++ ++ while (num > 1) { ++ i++; ++ num = num >> 1; ++ } ++ ++ return (i); ++} ++ ++/* Checksum Functions */ ++static void ++zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp) ++{ ++ ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0); ++} ++ ++/* Checksum Table and Values */ ++zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = { ++ NULL, NULL, 0, 0, "inherit", ++ NULL, NULL, 0, 0, "on", ++ zio_checksum_off, zio_checksum_off, 0, 0, "off", ++ zio_checksum_SHA256, zio_checksum_SHA256, 1, 1, "label", ++ zio_checksum_SHA256, zio_checksum_SHA256, 1, 1, "gang_header", ++ NULL, NULL, 0, 0, "zilog", ++ fletcher_2_native, fletcher_2_byteswap, 0, 0, "fletcher2", ++ fletcher_4_native, fletcher_4_byteswap, 1, 0, "fletcher4", ++ zio_checksum_SHA256, zio_checksum_SHA256, 1, 0, "SHA256", ++ NULL, NULL, 0, 0, "zilog2", ++}; ++ ++/* ++ * zio_checksum_verify: Provides support for checksum verification. ++ * ++ * Fletcher2, Fletcher4, and SHA256 are supported. ++ * ++ * Return: ++ * -1 = Failure ++ * 0 = Success ++ */ ++static int ++zio_checksum_verify(blkptr_t *bp, char *data, int size) ++{ ++ zio_cksum_t zc = bp->blk_cksum; ++ uint32_t checksum = BP_GET_CHECKSUM(bp); ++ int byteswap = BP_SHOULD_BYTESWAP(bp); ++ zio_eck_t *zec = (zio_eck_t *)(data + size) - 1; ++ zio_checksum_info_t *ci = &zio_checksum_table[checksum]; ++ zio_cksum_t actual_cksum, expected_cksum; ++ ++ /* byteswap is not supported */ ++ if (byteswap) ++ return (-1); ++ ++ if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL) ++ return (-1); ++ ++ if (ci->ci_eck) { ++ expected_cksum = zec->zec_cksum; ++ zec->zec_cksum = zc; ++ ci->ci_func[0](data, size, &actual_cksum); ++ zec->zec_cksum = expected_cksum; ++ zc = expected_cksum; ++ ++ } else { ++ ci->ci_func[byteswap](data, size, &actual_cksum); ++ } ++ ++ if ((actual_cksum.zc_word[0] - zc.zc_word[0]) | ++ (actual_cksum.zc_word[1] - zc.zc_word[1]) | ++ (actual_cksum.zc_word[2] - zc.zc_word[2]) | ++ (actual_cksum.zc_word[3] - zc.zc_word[3])) ++ return (-1); ++ ++ return (0); ++} ++ ++/* ++ * vdev_label_start returns the physical disk offset (in bytes) of ++ * label "l". ++ */ ++static uint64_t ++vdev_label_start(uint64_t psize, int l) ++{ ++ return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ? ++ 0 : psize - VDEV_LABELS * sizeof (vdev_label_t))); ++} ++ ++/* ++ * vdev_uberblock_compare takes two uberblock structures and returns an integer ++ * indicating the more recent of the two. ++ * Return Value = 1 if ub2 is more recent ++ * Return Value = -1 if ub1 is more recent ++ * The most recent uberblock is determined using its transaction number and ++ * timestamp. The uberblock with the highest transaction number is ++ * considered "newer". If the transaction numbers of the two blocks match, the ++ * timestamps are compared to determine the "newer" of the two. ++ */ ++static int ++vdev_uberblock_compare(uberblock_t *ub1, uberblock_t *ub2) ++{ ++ if (ub1->ub_txg < ub2->ub_txg) ++ return (-1); ++ if (ub1->ub_txg > ub2->ub_txg) ++ return (1); ++ ++ if (ub1->ub_timestamp < ub2->ub_timestamp) ++ return (-1); ++ if (ub1->ub_timestamp > ub2->ub_timestamp) ++ return (1); ++ ++ return (0); ++} ++ ++/* ++ * Three pieces of information are needed to verify an uberblock: the magic ++ * number, the version number, and the checksum. ++ * ++ * Currently Implemented: version number, magic number ++ * Need to Implement: checksum ++ * ++ * Return: ++ * 0 - Success ++ * -1 - Failure ++ */ ++static int ++uberblock_verify(uberblock_phys_t *ub, uint64_t offset) ++{ ++ ++ uberblock_t *uber = &ub->ubp_uberblock; ++ blkptr_t bp; ++ ++ BP_ZERO(&bp); ++ BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); ++ BP_SET_BYTEORDER(&bp, ZFS_HOST_BYTEORDER); ++ ZIO_SET_CHECKSUM(&bp.blk_cksum, offset, 0, 0, 0); ++ ++ if (zio_checksum_verify(&bp, (char *)ub, UBERBLOCK_SIZE) != 0) ++ return (-1); ++ ++ if (uber->ub_magic == UBERBLOCK_MAGIC && ++ uber->ub_version > 0 && uber->ub_version <= SPA_VERSION) ++ return (0); ++ ++ return (-1); ++} ++ ++/* ++ * Find the best uberblock. ++ * Return: ++ * Success - Pointer to the best uberblock. ++ * Failure - NULL ++ */ ++static uberblock_phys_t * ++find_bestub(uberblock_phys_t *ub_array, uint64_t sector) ++{ ++ uberblock_phys_t *ubbest = NULL; ++ uint64_t offset; ++ int i; ++ ++ for (i = 0; i < (VDEV_UBERBLOCK_RING >> VDEV_UBERBLOCK_SHIFT); i++) { ++ offset = (sector << SPA_MINBLOCKSHIFT) + ++ VDEV_UBERBLOCK_OFFSET(i); ++ if (uberblock_verify(&ub_array[i], offset) == 0) { ++ if (ubbest == NULL) { ++ ubbest = &ub_array[i]; ++ } else if (vdev_uberblock_compare( ++ &(ub_array[i].ubp_uberblock), ++ &(ubbest->ubp_uberblock)) > 0) { ++ ubbest = &ub_array[i]; ++ } ++ } ++ } ++ ++ return (ubbest); ++} ++ ++/* ++ * Read a block of data based on the gang block address dva, ++ * and put its data in buf. ++ * ++ * Return: ++ * 0 - success ++ * 1 - failure ++ */ ++static int ++zio_read_gang(blkptr_t *bp, dva_t *dva, void *buf, char *stack) ++{ ++ zio_gbh_phys_t *zio_gb; ++ uint64_t offset, sector; ++ blkptr_t tmpbp; ++ int i; ++ ++ zio_gb = (zio_gbh_phys_t *)stack; ++ stack += SPA_GANGBLOCKSIZE; ++ offset = DVA_GET_OFFSET(dva); ++ sector = DVA_OFFSET_TO_PHYS_SECTOR(offset); ++ ++ /* read in the gang block header */ ++ if (devread(sector, 0, SPA_GANGBLOCKSIZE, (char *)zio_gb) == 0) { ++ grub_printf("failed to read in a gang block header\n"); ++ return (1); ++ } ++ ++ /* self checksuming the gang block header */ ++ BP_ZERO(&tmpbp); ++ BP_SET_CHECKSUM(&tmpbp, ZIO_CHECKSUM_GANG_HEADER); ++ BP_SET_BYTEORDER(&tmpbp, ZFS_HOST_BYTEORDER); ++ ZIO_SET_CHECKSUM(&tmpbp.blk_cksum, DVA_GET_VDEV(dva), ++ DVA_GET_OFFSET(dva), bp->blk_birth, 0); ++ if (zio_checksum_verify(&tmpbp, (char *)zio_gb, SPA_GANGBLOCKSIZE)) { ++ grub_printf("failed to checksum a gang block header\n"); ++ return (1); ++ } ++ ++ for (i = 0; i < SPA_GBH_NBLKPTRS; i++) { ++ if (zio_gb->zg_blkptr[i].blk_birth == 0) ++ continue; ++ ++ if (zio_read_data(&zio_gb->zg_blkptr[i], buf, stack)) ++ return (1); ++ buf += BP_GET_PSIZE(&zio_gb->zg_blkptr[i]); ++ } ++ ++ return (0); ++} ++ ++/* ++ * Read in a block of raw data to buf. ++ * ++ * Return: ++ * 0 - success ++ * 1 - failure ++ */ ++static int ++zio_read_data(blkptr_t *bp, void *buf, char *stack) ++{ ++ int i, psize; ++ ++ psize = BP_GET_PSIZE(bp); ++ ++ /* pick a good dva from the block pointer */ ++ for (i = 0; i < SPA_DVAS_PER_BP; i++) { ++ uint64_t offset, sector; ++ ++ if (bp->blk_dva[i].dva_word[0] == 0 && ++ bp->blk_dva[i].dva_word[1] == 0) ++ continue; ++ ++ if (DVA_GET_GANG(&bp->blk_dva[i])) { ++ if (zio_read_gang(bp, &bp->blk_dva[i], buf, stack) == 0) ++ return (0); ++ } else { ++ /* read in a data block */ ++ offset = DVA_GET_OFFSET(&bp->blk_dva[i]); ++ sector = DVA_OFFSET_TO_PHYS_SECTOR(offset); ++ if (devread(sector, 0, psize, buf)) ++ return (0); ++ } ++ } ++ ++ return (1); ++} ++ ++/* ++ * Read in a block of data, verify its checksum, decompress if needed, ++ * and put the uncompressed data in buf. ++ * ++ * Return: ++ * 0 - success ++ * errnum - failure ++ */ ++static int ++zio_read(blkptr_t *bp, void *buf, char *stack) ++{ ++ int lsize, psize, comp; ++ char *retbuf; ++ ++ comp = BP_GET_COMPRESS(bp); ++ lsize = BP_GET_LSIZE(bp); ++ psize = BP_GET_PSIZE(bp); ++ ++ if ((unsigned int)comp >= ZIO_COMPRESS_FUNCTIONS || ++ (comp != ZIO_COMPRESS_OFF && ++ decomp_table[comp].decomp_func == NULL)) { ++ grub_printf("compression algorithm not supported\n"); ++ return (ERR_FSYS_CORRUPT); ++ } ++ ++ if ((char *)buf < stack && ((char *)buf) + lsize > stack) { ++ grub_printf("not enough memory allocated\n"); ++ return (ERR_WONT_FIT); ++ } ++ ++ retbuf = buf; ++ if (comp != ZIO_COMPRESS_OFF) { ++ buf = stack; ++ stack += psize; ++ } ++ ++ if (zio_read_data(bp, buf, stack)) { ++ grub_printf("zio_read_data failed\n"); ++ return (ERR_FSYS_CORRUPT); ++ } ++ ++ if (zio_checksum_verify(bp, buf, psize) != 0) { ++ grub_printf("checksum verification failed\n"); ++ return (ERR_FSYS_CORRUPT); ++ } ++ ++ if (comp != ZIO_COMPRESS_OFF) ++ decomp_table[comp].decomp_func(buf, retbuf, psize, lsize); ++ ++ return (0); ++} ++ ++/* ++ * Get the block from a block id. ++ * push the block onto the stack. ++ * ++ * Return: ++ * 0 - success ++ * errnum - failure ++ */ ++static int ++dmu_read(dnode_phys_t *dn, uint64_t blkid, void *buf, char *stack) ++{ ++ int idx, level; ++ blkptr_t *bp_array = dn->dn_blkptr; ++ int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT; ++ blkptr_t *bp, *tmpbuf; ++ ++ bp = (blkptr_t *)stack; ++ stack += sizeof (blkptr_t); ++ ++ tmpbuf = (blkptr_t *)stack; ++ stack += 1<dn_indblkshift; ++ ++ for (level = dn->dn_nlevels - 1; level >= 0; level--) { ++ idx = (blkid >> (epbs * level)) & ((1<dn_datablkszsec << SPA_MINBLOCKSHIFT); ++ break; ++ } else if (errnum = zio_read(bp, tmpbuf, stack)) { ++ return (errnum); ++ } ++ ++ bp_array = tmpbuf; ++ } ++ ++ return (0); ++} ++ ++/* ++ * mzap_lookup: Looks up property described by "name" and returns the value ++ * in "value". ++ * ++ * Return: ++ * 0 - success ++ * errnum - failure ++ */ ++static int ++mzap_lookup(mzap_phys_t *zapobj, int objsize, char *name, ++ uint64_t *value) ++{ ++ int i, chunks; ++ mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; ++ ++ chunks = objsize/MZAP_ENT_LEN - 1; ++ for (i = 0; i < chunks; i++) { ++ if (grub_strcmp(mzap_ent[i].mze_name, name) == 0) { ++ *value = mzap_ent[i].mze_value; ++ return (0); ++ } ++ } ++ ++ return (ERR_FSYS_CORRUPT); ++} ++ ++static uint64_t ++zap_hash(uint64_t salt, const char *name) ++{ ++ static uint64_t table[256]; ++ const uint8_t *cp; ++ uint8_t c; ++ uint64_t crc = salt; ++ ++ if (table[128] == 0) { ++ uint64_t *ct; ++ int i, j; ++ for (i = 0; i < 256; i++) { ++ for (ct = table + i, *ct = i, j = 8; j > 0; j--) ++ *ct = (*ct >> 1) ^ (-(*ct & 1) & ++ ZFS_CRC64_POLY); ++ } ++ } ++ ++ if (crc == 0 || table[128] != ZFS_CRC64_POLY) { ++ errnum = ERR_FSYS_CORRUPT; ++ return (0); ++ } ++ ++ for (cp = (const uint8_t *)name; (c = *cp) != '\0'; cp++) ++ crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF]; ++ ++ /* ++ * Only use 28 bits, since we need 4 bits in the cookie for the ++ * collision differentiator. We MUST use the high bits, since ++ * those are the onces that we first pay attention to when ++ * chosing the bucket. ++ */ ++ crc &= ~((1ULL << (64 - 28)) - 1); ++ ++ return (crc); ++} ++ ++/* ++ * Only to be used on 8-bit arrays. ++ * array_len is actual len in bytes (not encoded le_value_length). ++ * buf is null-terminated. ++ */ ++static int ++zap_leaf_array_equal(zap_leaf_phys_t *l, int blksft, int chunk, ++ int array_len, const char *buf) ++{ ++ int bseen = 0; ++ ++ while (bseen < array_len) { ++ struct zap_leaf_array *la = ++ &ZAP_LEAF_CHUNK(l, blksft, chunk).l_array; ++ int toread = MIN(array_len - bseen, ZAP_LEAF_ARRAY_BYTES); ++ ++ if (chunk >= ZAP_LEAF_NUMCHUNKS(blksft)) ++ return (0); ++ ++ if (zfs_bcmp(la->la_array, buf + bseen, toread) != 0) ++ break; ++ chunk = la->la_next; ++ bseen += toread; ++ } ++ return (bseen == array_len); ++} ++ ++/* ++ * Given a zap_leaf_phys_t, walk thru the zap leaf chunks to get the ++ * value for the property "name". ++ * ++ * Return: ++ * 0 - success ++ * errnum - failure ++ */ ++static int ++zap_leaf_lookup(zap_leaf_phys_t *l, int blksft, uint64_t h, ++ const char *name, uint64_t *value) ++{ ++ uint16_t chunk; ++ struct zap_leaf_entry *le; ++ ++ /* Verify if this is a valid leaf block */ ++ if (l->l_hdr.lh_block_type != ZBT_LEAF) ++ return (ERR_FSYS_CORRUPT); ++ if (l->l_hdr.lh_magic != ZAP_LEAF_MAGIC) ++ return (ERR_FSYS_CORRUPT); ++ ++ for (chunk = l->l_hash[LEAF_HASH(blksft, h)]; ++ chunk != CHAIN_END; chunk = le->le_next) { ++ ++ if (chunk >= ZAP_LEAF_NUMCHUNKS(blksft)) ++ return (ERR_FSYS_CORRUPT); ++ ++ le = ZAP_LEAF_ENTRY(l, blksft, chunk); ++ ++ /* Verify the chunk entry */ ++ if (le->le_type != ZAP_CHUNK_ENTRY) ++ return (ERR_FSYS_CORRUPT); ++ ++ if (le->le_hash != h) ++ continue; ++ ++ if (zap_leaf_array_equal(l, blksft, le->le_name_chunk, ++ le->le_name_length, name)) { ++ ++ struct zap_leaf_array *la; ++ uint8_t *ip; ++ ++ if (le->le_int_size != 8 || le->le_value_length != 1) ++ return (ERR_FSYS_CORRUPT); ++ ++ /* get the uint64_t property value */ ++ la = &ZAP_LEAF_CHUNK(l, blksft, ++ le->le_value_chunk).l_array; ++ ip = la->la_array; ++ ++ *value = (uint64_t)ip[0] << 56 | (uint64_t)ip[1] << 48 | ++ (uint64_t)ip[2] << 40 | (uint64_t)ip[3] << 32 | ++ (uint64_t)ip[4] << 24 | (uint64_t)ip[5] << 16 | ++ (uint64_t)ip[6] << 8 | (uint64_t)ip[7]; ++ ++ return (0); ++ } ++ } ++ ++ return (ERR_FSYS_CORRUPT); ++} ++ ++/* ++ * Fat ZAP lookup ++ * ++ * Return: ++ * 0 - success ++ * errnum - failure ++ */ ++static int ++fzap_lookup(dnode_phys_t *zap_dnode, zap_phys_t *zap, ++ char *name, uint64_t *value, char *stack) ++{ ++ zap_leaf_phys_t *l; ++ uint64_t hash, idx, blkid; ++ int blksft = zfs_log2(zap_dnode->dn_datablkszsec << DNODE_SHIFT); ++ ++ /* Verify if this is a fat zap header block */ ++ if (zap->zap_magic != (uint64_t)ZAP_MAGIC || ++ zap->zap_flags != 0) ++ return (ERR_FSYS_CORRUPT); ++ ++ hash = zap_hash(zap->zap_salt, name); ++ if (errnum) ++ return (errnum); ++ ++ /* get block id from index */ ++ if (zap->zap_ptrtbl.zt_numblks != 0) { ++ /* external pointer tables not supported */ ++ return (ERR_FSYS_CORRUPT); ++ } ++ idx = ZAP_HASH_IDX(hash, zap->zap_ptrtbl.zt_shift); ++ blkid = ((uint64_t *)zap)[idx + (1<<(blksft-3-1))]; ++ ++ /* Get the leaf block */ ++ l = (zap_leaf_phys_t *)stack; ++ stack += 1<dn_datablkszsec << SPA_MINBLOCKSHIFT; ++ stack += size; ++ ++ if (errnum = dmu_read(zap_dnode, 0, zapbuf, stack)) ++ return (errnum); ++ ++ block_type = *((uint64_t *)zapbuf); ++ ++ if (block_type == ZBT_MICRO) { ++ return (mzap_lookup(zapbuf, size, name, val)); ++ } else if (block_type == ZBT_HEADER) { ++ /* this is a fat zap */ ++ return (fzap_lookup(zap_dnode, zapbuf, name, ++ val, stack)); ++ } ++ ++ return (ERR_FSYS_CORRUPT); ++} ++ ++/* ++ * Get the dnode of an object number from the metadnode of an object set. ++ * ++ * Input ++ * mdn - metadnode to get the object dnode ++ * objnum - object number for the object dnode ++ * buf - data buffer that holds the returning dnode ++ * stack - scratch area ++ * ++ * Return: ++ * 0 - success ++ * errnum - failure ++ */ ++static int ++dnode_get(dnode_phys_t *mdn, uint64_t objnum, uint8_t type, dnode_phys_t *buf, ++ char *stack) ++{ ++ uint64_t blkid, blksz; /* the block id this object dnode is in */ ++ int epbs; /* shift of number of dnodes in a block */ ++ int idx; /* index within a block */ ++ dnode_phys_t *dnbuf; ++ ++ blksz = mdn->dn_datablkszsec << SPA_MINBLOCKSHIFT; ++ epbs = zfs_log2(blksz) - DNODE_SHIFT; ++ blkid = objnum >> epbs; ++ idx = objnum & ((1<= dnode_start && objnum < dnode_end) { ++ grub_memmove(buf, &dnode_buf[idx], DNODE_SIZE); ++ VERIFY_DN_TYPE(buf, type); ++ return (0); ++ } ++ ++ if (dnode_buf && blksz == 1< ZPL_VERSION) ++ return (-1); ++ ++ if (errnum = zap_lookup(dn, ZFS_ROOT_OBJ, &objnum, stack)) ++ return (errnum); ++ ++ if (errnum = dnode_get(mdn, objnum, DMU_OT_DIRECTORY_CONTENTS, ++ dn, stack)) ++ return (errnum); ++ ++ /* skip leading slashes */ ++ while (*path == '/') ++ path++; ++ ++ while (*path && !isspace(*path)) { ++ ++ /* get the next component name */ ++ cname = path; ++ while (*path && !isspace(*path) && *path != '/') ++ path++; ++ ch = *path; ++ *path = 0; /* ensure null termination */ ++ ++ if (errnum = zap_lookup(dn, cname, &objnum, stack)) ++ return (errnum); ++ ++ objnum = ZFS_DIRENT_OBJ(objnum); ++ if (errnum = dnode_get(mdn, objnum, 0, dn, stack)) ++ return (errnum); ++ ++ *path = ch; ++ while (*path == '/') ++ path++; ++ } ++ ++ /* We found the dnode for this file. Verify if it is a plain file. */ ++ VERIFY_DN_TYPE(dn, DMU_OT_PLAIN_FILE_CONTENTS); ++ ++ return (0); ++} ++ ++/* ++ * Get the default 'bootfs' property value from the rootpool. ++ * ++ * Return: ++ * 0 - success ++ * errnum -failure ++ */ ++static int ++get_default_bootfsobj(dnode_phys_t *mosmdn, uint64_t *obj, char *stack) ++{ ++ uint64_t objnum = 0; ++ dnode_phys_t *dn = (dnode_phys_t *)stack; ++ stack += DNODE_SIZE; ++ ++ if (errnum = dnode_get(mosmdn, DMU_POOL_DIRECTORY_OBJECT, ++ DMU_OT_OBJECT_DIRECTORY, dn, stack)) ++ return (errnum); ++ ++ /* ++ * find the object number for 'pool_props', and get the dnode ++ * of the 'pool_props'. ++ */ ++ if (zap_lookup(dn, DMU_POOL_PROPS, &objnum, stack)) ++ return (ERR_FILESYSTEM_NOT_FOUND); ++ ++ if (errnum = dnode_get(mosmdn, objnum, DMU_OT_POOL_PROPS, dn, stack)) ++ return (errnum); ++ ++ if (zap_lookup(dn, ZPOOL_PROP_BOOTFS, &objnum, stack)) ++ return (ERR_FILESYSTEM_NOT_FOUND); ++ ++ if (!objnum) ++ return (ERR_FILESYSTEM_NOT_FOUND); ++ ++ *obj = objnum; ++ return (0); ++} ++ ++/* ++ * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname), ++ * e.g. pool/rootfs, or a given object number (obj), e.g. the object number ++ * of pool/rootfs. ++ * ++ * If no fsname and no obj are given, return the DSL_DIR metadnode. ++ * If fsname is given, return its metadnode and its matching object number. ++ * If only obj is given, return the metadnode for this object number. ++ * ++ * Return: ++ * 0 - success ++ * errnum - failure ++ */ ++static int ++get_objset_mdn(dnode_phys_t *mosmdn, char *fsname, uint64_t *obj, ++ dnode_phys_t *mdn, char *stack) ++{ ++ uint64_t objnum, headobj; ++ char *cname, ch; ++ blkptr_t *bp; ++ objset_phys_t *osp; ++ int issnapshot = 0; ++ char *snapname; ++ ++ if (fsname == NULL && obj) { ++ headobj = *obj; ++ goto skip; ++ } ++ ++ if (errnum = dnode_get(mosmdn, DMU_POOL_DIRECTORY_OBJECT, ++ DMU_OT_OBJECT_DIRECTORY, mdn, stack)) ++ return (errnum); ++ ++ if (errnum = zap_lookup(mdn, DMU_POOL_ROOT_DATASET, &objnum, ++ stack)) ++ return (errnum); ++ ++ if (errnum = dnode_get(mosmdn, objnum, DMU_OT_DSL_DIR, mdn, stack)) ++ return (errnum); ++ ++ if (fsname == NULL) { ++ headobj = ++ ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_head_dataset_obj; ++ goto skip; ++ } ++ ++ /* take out the pool name */ ++ while (*fsname && !isspace(*fsname) && *fsname != '/') ++ fsname++; ++ ++ while (*fsname && !isspace(*fsname)) { ++ uint64_t childobj; ++ ++ while (*fsname == '/') ++ fsname++; ++ ++ cname = fsname; ++ while (*fsname && !isspace(*fsname) && *fsname != '/') ++ fsname++; ++ ch = *fsname; ++ *fsname = 0; ++ ++ snapname = cname; ++ while (*snapname && !isspace(*snapname) && *snapname != '@') ++ snapname++; ++ if (*snapname == '@') { ++ issnapshot = 1; ++ *snapname = 0; ++ } ++ childobj = ++ ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_child_dir_zapobj; ++ if (childobj == 0) ++ return (ERR_FILESYSTEM_NOT_FOUND); ++ if (errnum = dnode_get(mosmdn, childobj, ++ DMU_OT_DSL_DIR_CHILD_MAP, mdn, stack)) ++ return (errnum); ++ ++ if (zap_lookup(mdn, cname, &objnum, stack)) ++ return (ERR_FILESYSTEM_NOT_FOUND); ++ ++ if (errnum = dnode_get(mosmdn, objnum, DMU_OT_DSL_DIR, ++ mdn, stack)) ++ return (errnum); ++ ++ *fsname = ch; ++ if (issnapshot) ++ *snapname = '@'; ++ } ++ headobj = ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_head_dataset_obj; ++ if (obj) ++ *obj = headobj; ++ ++skip: ++ if (errnum = dnode_get(mosmdn, headobj, DMU_OT_DSL_DATASET, mdn, stack)) ++ return (errnum); ++ if (issnapshot) { ++ uint64_t snapobj; ++ ++ snapobj = ((dsl_dataset_phys_t *)DN_BONUS(mdn))-> ++ ds_snapnames_zapobj; ++ ++ if (errnum = dnode_get(mosmdn, snapobj, ++ DMU_OT_DSL_DS_SNAP_MAP, mdn, stack)) ++ return (errnum); ++ if (zap_lookup(mdn, snapname + 1, &headobj, stack)) ++ return (ERR_FILESYSTEM_NOT_FOUND); ++ if (errnum = dnode_get(mosmdn, headobj, ++ DMU_OT_DSL_DATASET, mdn, stack)) ++ return (errnum); ++ if (obj) ++ *obj = headobj; ++ } ++ ++ bp = &((dsl_dataset_phys_t *)DN_BONUS(mdn))->ds_bp; ++ osp = (objset_phys_t *)stack; ++ stack += sizeof (objset_phys_t); ++ if (errnum = zio_read(bp, osp, stack)) ++ return (errnum); ++ ++ grub_memmove((char *)mdn, (char *)&osp->os_meta_dnode, DNODE_SIZE); ++ ++ return (0); ++} ++ ++/* ++ * For a given XDR packed nvlist, verify the first 4 bytes and move on. ++ * ++ * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) : ++ * ++ * encoding method/host endian (4 bytes) ++ * nvl_version (4 bytes) ++ * nvl_nvflag (4 bytes) ++ * encoded nvpairs: ++ * encoded size of the nvpair (4 bytes) ++ * decoded size of the nvpair (4 bytes) ++ * name string size (4 bytes) ++ * name string data (sizeof(NV_ALIGN4(string)) ++ * data type (4 bytes) ++ * # of elements in the nvpair (4 bytes) ++ * data ++ * 2 zero's for the last nvpair ++ * (end of the entire list) (8 bytes) ++ * ++ * Return: ++ * 0 - success ++ * 1 - failure ++ */ ++static int ++nvlist_unpack(char *nvlist, char **out) ++{ ++ /* Verify if the 1st and 2nd byte in the nvlist are valid. */ ++ if (nvlist[0] != NV_ENCODE_XDR || nvlist[1] != HOST_ENDIAN) ++ return (1); ++ ++ nvlist += 4; ++ *out = nvlist; ++ return (0); ++} ++ ++static char * ++nvlist_array(char *nvlist, int index) ++{ ++ int i, encode_size; ++ ++ for (i = 0; i < index; i++) { ++ /* skip the header, nvl_version, and nvl_nvflag */ ++ nvlist = nvlist + 4 * 2; ++ ++ while (encode_size = BSWAP_32(*(uint32_t *)nvlist)) ++ nvlist += encode_size; /* goto the next nvpair */ ++ ++ nvlist = nvlist + 4 * 2; /* skip the ending 2 zeros - 8 bytes */ ++ } ++ ++ return (nvlist); ++} ++ ++static int ++nvlist_lookup_value(char *nvlist, char *name, void *val, int valtype, ++ int *nelmp) ++{ ++ int name_len, type, slen, encode_size; ++ char *nvpair, *nvp_name, *strval = val; ++ uint64_t *intval = val; ++ ++ /* skip the header, nvl_version, and nvl_nvflag */ ++ nvlist = nvlist + 4 * 2; ++ ++ /* ++ * Loop thru the nvpair list ++ * The XDR representation of an integer is in big-endian byte order. ++ */ ++ while (encode_size = BSWAP_32(*(uint32_t *)nvlist)) { ++ ++ nvpair = nvlist + 4 * 2; /* skip the encode/decode size */ ++ ++ name_len = BSWAP_32(*(uint32_t *)nvpair); ++ nvpair += 4; ++ ++ nvp_name = nvpair; ++ nvpair = nvpair + ((name_len + 3) & ~3); /* align */ ++ ++ type = BSWAP_32(*(uint32_t *)nvpair); ++ nvpair += 4; ++ ++ if ((grub_strncmp(nvp_name, name, name_len) == 0) && ++ type == valtype) { ++ int nelm; ++ ++ if ((nelm = BSWAP_32(*(uint32_t *)nvpair)) < 1) ++ return (1); ++ nvpair += 4; ++ ++ switch (valtype) { ++ case DATA_TYPE_STRING: ++ slen = BSWAP_32(*(uint32_t *)nvpair); ++ nvpair += 4; ++ grub_memmove(strval, nvpair, slen); ++ strval[slen] = '\0'; ++ return (0); ++ ++ case DATA_TYPE_UINT64: ++ *intval = BSWAP_64(*(uint64_t *)nvpair); ++ return (0); ++ ++ case DATA_TYPE_NVLIST: ++ *(void **)val = (void *)nvpair; ++ return (0); ++ ++ case DATA_TYPE_NVLIST_ARRAY: ++ *(void **)val = (void *)nvpair; ++ if (nelmp) ++ *nelmp = nelm; ++ return (0); ++ } ++ } ++ ++ nvlist += encode_size; /* goto the next nvpair */ ++ } ++ ++ return (1); ++} ++ ++/* ++ * Check if this vdev is online and is in a good state. ++ */ ++static int ++vdev_validate(char *nv) ++{ ++ uint64_t ival; ++ ++ if (nvlist_lookup_value(nv, ZPOOL_CONFIG_OFFLINE, &ival, ++ DATA_TYPE_UINT64, NULL) == 0 || ++ nvlist_lookup_value(nv, ZPOOL_CONFIG_FAULTED, &ival, ++ DATA_TYPE_UINT64, NULL) == 0 || ++ nvlist_lookup_value(nv, ZPOOL_CONFIG_REMOVED, &ival, ++ DATA_TYPE_UINT64, NULL) == 0) ++ return (ERR_DEV_VALUES); ++ ++ return (0); ++} ++ ++/* ++ * Get a valid vdev pathname/devid from the boot device. ++ * The caller should already allocate MAXPATHLEN memory for bootpath and devid. ++ */ ++static int ++vdev_get_bootpath(char *nv, uint64_t inguid, char *devid, char *bootpath, ++ int is_spare) ++{ ++ char type[16]; ++ ++ if (nvlist_lookup_value(nv, ZPOOL_CONFIG_TYPE, &type, DATA_TYPE_STRING, ++ NULL)) ++ return (ERR_FSYS_CORRUPT); ++ ++ if (strcmp(type, VDEV_TYPE_DISK) == 0) { ++ uint64_t guid; ++ ++ if (vdev_validate(nv) != 0) ++ return (ERR_NO_BOOTPATH); ++ ++ if (nvlist_lookup_value(nv, ZPOOL_CONFIG_GUID, ++ &guid, DATA_TYPE_UINT64, NULL) != 0) ++ return (ERR_NO_BOOTPATH); ++ ++ if (guid != inguid) ++ return (ERR_NO_BOOTPATH); ++ ++ /* for a spare vdev, pick the disk labeled with "is_spare" */ ++ if (is_spare) { ++ uint64_t spare = 0; ++ (void) nvlist_lookup_value(nv, ZPOOL_CONFIG_IS_SPARE, ++ &spare, DATA_TYPE_UINT64, NULL); ++ if (!spare) ++ return (ERR_NO_BOOTPATH); ++ } ++ ++ if (nvlist_lookup_value(nv, ZPOOL_CONFIG_PHYS_PATH, ++ bootpath, DATA_TYPE_STRING, NULL) != 0) ++ bootpath[0] = '\0'; ++ ++ if (nvlist_lookup_value(nv, ZPOOL_CONFIG_DEVID, ++ devid, DATA_TYPE_STRING, NULL) != 0) ++ devid[0] = '\0'; ++ ++ if (strlen(bootpath) >= MAXPATHLEN || ++ strlen(devid) >= MAXPATHLEN) ++ return (ERR_WONT_FIT); ++ ++ return (0); ++ ++ } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || ++ strcmp(type, VDEV_TYPE_REPLACING) == 0 || ++ (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { ++ int nelm, i; ++ char *child; ++ ++ if (nvlist_lookup_value(nv, ZPOOL_CONFIG_CHILDREN, &child, ++ DATA_TYPE_NVLIST_ARRAY, &nelm)) ++ return (ERR_FSYS_CORRUPT); ++ ++ for (i = 0; i < nelm; i++) { ++ char *child_i; ++ ++ child_i = nvlist_array(child, i); ++ if (vdev_get_bootpath(child_i, inguid, devid, ++ bootpath, is_spare) == 0) ++ return (0); ++ } ++ } ++ ++ return (ERR_NO_BOOTPATH); ++} ++ ++/* ++ * Check the disk label information and retrieve needed vdev name-value pairs. ++ * ++ * Return: ++ * 0 - success ++ * ERR_* - failure ++ */ ++int ++check_pool_label(uint64_t sector, char *stack, char *outdevid, ++ char *outpath, uint64_t *outguid) ++{ ++ vdev_phys_t *vdev; ++ uint64_t pool_state, txg = 0; ++ char *nvlist, *nv; ++ uint64_t diskguid; ++ uint64_t version; ++ ++ sector += (VDEV_SKIP_SIZE >> SPA_MINBLOCKSHIFT); ++ ++ /* Read in the vdev name-value pair list (112K). */ ++ if (devread(sector, 0, VDEV_PHYS_SIZE, stack) == 0) ++ return (ERR_READ); ++ ++ vdev = (vdev_phys_t *)stack; ++ stack += sizeof (vdev_phys_t); ++ ++ if (nvlist_unpack(vdev->vp_nvlist, &nvlist)) ++ return (ERR_FSYS_CORRUPT); ++ ++ if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_POOL_STATE, &pool_state, ++ DATA_TYPE_UINT64, NULL)) ++ return (ERR_FSYS_CORRUPT); ++ ++ if (pool_state == POOL_STATE_DESTROYED) ++ return (ERR_FILESYSTEM_NOT_FOUND); ++ ++ if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_POOL_NAME, ++ current_rootpool, DATA_TYPE_STRING, NULL)) ++ return (ERR_FSYS_CORRUPT); ++ ++ if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_POOL_TXG, &txg, ++ DATA_TYPE_UINT64, NULL)) ++ return (ERR_FSYS_CORRUPT); ++ ++ /* not an active device */ ++ if (txg == 0) ++ return (ERR_NO_BOOTPATH); ++ ++ if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_VERSION, &version, ++ DATA_TYPE_UINT64, NULL)) ++ return (ERR_FSYS_CORRUPT); ++ if (version > SPA_VERSION) ++ return (ERR_NEWER_VERSION); ++ if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_VDEV_TREE, &nv, ++ DATA_TYPE_NVLIST, NULL)) ++ return (ERR_FSYS_CORRUPT); ++ if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_GUID, &diskguid, ++ DATA_TYPE_UINT64, NULL)) ++ return (ERR_FSYS_CORRUPT); ++ if (vdev_get_bootpath(nv, diskguid, outdevid, outpath, 0)) ++ return (ERR_NO_BOOTPATH); ++ if (nvlist_lookup_value(nvlist, ZPOOL_CONFIG_POOL_GUID, outguid, ++ DATA_TYPE_UINT64, NULL)) ++ return (ERR_FSYS_CORRUPT); ++ return (0); ++} ++ ++/* ++ * zfs_mount() locates a valid uberblock of the root pool and read in its MOS ++ * to the memory address MOS. ++ * ++ * Return: ++ * 1 - success ++ * 0 - failure ++ */ ++int ++zfs_mount(void) ++{ ++ char *stack; ++ int label = 0; ++ uberblock_phys_t *ub_array, *ubbest; ++ objset_phys_t *osp; ++ char tmp_bootpath[MAXNAMELEN]; ++ char tmp_devid[MAXNAMELEN]; ++ uint64_t tmp_guid; ++ uint64_t adjpl = (uint64_t)part_length << SPA_MINBLOCKSHIFT; ++ int err = errnum; /* preserve previous errnum state */ ++ ++ /* if it's our first time here, zero the best uberblock out */ ++ if (best_drive == 0 && best_part == 0 && find_best_root) { ++ grub_memset(¤t_uberblock, 0, sizeof (uberblock_t)); ++ pool_guid = 0; ++ } ++ ++ stackbase = ZFS_SCRATCH; ++ stack = stackbase; ++ ub_array = (uberblock_phys_t *)stack; ++ stack += VDEV_UBERBLOCK_RING; ++ ++ osp = (objset_phys_t *)stack; ++ stack += sizeof (objset_phys_t); ++ adjpl = P2ALIGN(adjpl, (uint64_t)sizeof (vdev_label_t)); ++ ++ for (label = 0; label < VDEV_LABELS; label++) { ++ ++ /* ++ * some eltorito stacks don't give us a size and ++ * we end up setting the size to MAXUINT, further ++ * some of these devices stop working once a single ++ * read past the end has been issued. Checking ++ * for a maximum part_length and skipping the backup ++ * labels at the end of the slice/partition/device ++ * avoids breaking down on such devices. ++ */ ++ if (part_length == MAXUINT && label == 2) ++ break; ++ ++ uint64_t sector = vdev_label_start(adjpl, ++ label) >> SPA_MINBLOCKSHIFT; ++ ++ /* Read in the uberblock ring (128K). */ ++ if (devread(sector + ++ ((VDEV_SKIP_SIZE + VDEV_PHYS_SIZE) >> ++ SPA_MINBLOCKSHIFT), 0, VDEV_UBERBLOCK_RING, ++ (char *)ub_array) == 0) ++ continue; ++ ++ if ((ubbest = find_bestub(ub_array, sector)) != NULL && ++ zio_read(&ubbest->ubp_uberblock.ub_rootbp, osp, stack) ++ == 0) { ++ ++ VERIFY_OS_TYPE(osp, DMU_OST_META); ++ ++ if (check_pool_label(sector, stack, tmp_devid, ++ tmp_bootpath, &tmp_guid)) ++ continue; ++ if (pool_guid == 0) ++ pool_guid = tmp_guid; ++ ++ if (find_best_root && ((pool_guid != tmp_guid) || ++ vdev_uberblock_compare(&ubbest->ubp_uberblock, ++ &(current_uberblock)) <= 0)) ++ continue; ++ ++ /* Got the MOS. Save it at the memory addr MOS. */ ++ grub_memmove(MOS, &osp->os_meta_dnode, DNODE_SIZE); ++ grub_memmove(¤t_uberblock, ++ &ubbest->ubp_uberblock, sizeof (uberblock_t)); ++ grub_memmove(current_bootpath, tmp_bootpath, ++ MAXNAMELEN); ++ grub_memmove(current_devid, tmp_devid, ++ grub_strlen(tmp_devid)); ++ is_zfs_mount = 1; ++ return (1); ++ } ++ } ++ ++ /* ++ * While some fs impls. (tftp) rely on setting and keeping ++ * global errnums set, others won't reset it and will break ++ * when issuing rawreads. The goal here is to simply not ++ * have zfs mount attempts impact the previous state. ++ */ ++ errnum = err; ++ return (0); ++} ++ ++/* ++ * zfs_open() locates a file in the rootpool by following the ++ * MOS and places the dnode of the file in the memory address DNODE. ++ * ++ * Return: ++ * 1 - success ++ * 0 - failure ++ */ ++int ++zfs_open(char *filename) ++{ ++ char *stack; ++ dnode_phys_t *mdn; ++ ++ file_buf = NULL; ++ stackbase = ZFS_SCRATCH; ++ stack = stackbase; ++ ++ mdn = (dnode_phys_t *)stack; ++ stack += sizeof (dnode_phys_t); ++ ++ dnode_mdn = NULL; ++ dnode_buf = (dnode_phys_t *)stack; ++ stack += 1<dn_bonustype == DMU_OT_SA) { ++ sa_hdr_phys_t *sahdrp; ++ int hdrsize; ++ ++ if (DNODE->dn_bonuslen != 0) { ++ sahdrp = (sa_hdr_phys_t *)DN_BONUS(DNODE); ++ } else { ++ if (DNODE->dn_flags & DNODE_FLAG_SPILL_BLKPTR) { ++ blkptr_t *bp = &DNODE->dn_spill; ++ void *buf; ++ ++ buf = (void *)stack; ++ stack += BP_GET_LSIZE(bp); ++ ++ /* reset errnum to rawread() failure */ ++ errnum = 0; ++ if (zio_read(bp, buf, stack) != 0) { ++ return (0); ++ } ++ sahdrp = buf; ++ } else { ++ errnum = ERR_FSYS_CORRUPT; ++ return (0); ++ } ++ } ++ hdrsize = SA_HDR_SIZE(sahdrp); ++ filemax = *(uint64_t *)((char *)sahdrp + hdrsize + ++ SA_SIZE_OFFSET); ++ } else { ++ filemax = ((znode_phys_t *)DN_BONUS(DNODE))->zp_size; ++ } ++ filepos = 0; ++ ++ dnode_buf = NULL; ++ return (1); ++} ++ ++/* ++ * zfs_read reads in the data blocks pointed by the DNODE. ++ * ++ * Return: ++ * len - the length successfully read in to the buffer ++ * 0 - failure ++ */ ++int ++zfs_read(char *buf, int len) ++{ ++ char *stack; ++ char *tmpbuf; ++ int blksz, length, movesize; ++ ++ if (file_buf == NULL) { ++ file_buf = stackbase; ++ stackbase += SPA_MAXBLOCKSIZE; ++ file_start = file_end = 0; ++ } ++ stack = stackbase; ++ ++ /* ++ * If offset is in memory, move it into the buffer provided and return. ++ */ ++ if (filepos >= file_start && filepos+len <= file_end) { ++ grub_memmove(buf, file_buf + filepos - file_start, len); ++ filepos += len; ++ return (len); ++ } ++ ++ blksz = DNODE->dn_datablkszsec << SPA_MINBLOCKSHIFT; ++ ++ /* ++ * Entire Dnode is too big to fit into the space available. We ++ * will need to read it in chunks. This could be optimized to ++ * read in as large a chunk as there is space available, but for ++ * now, this only reads in one data block at a time. ++ */ ++ length = len; ++ while (length) { ++ /* ++ * Find requested blkid and the offset within that block. ++ */ ++ uint64_t blkid = filepos / blksz; ++ ++ if (errnum = dmu_read(DNODE, blkid, file_buf, stack)) ++ return (0); ++ ++ file_start = blkid * blksz; ++ file_end = file_start + blksz; ++ ++ movesize = MIN(length, file_end - filepos); ++ ++ grub_memmove(buf, file_buf + filepos - file_start, ++ movesize); ++ buf += movesize; ++ length -= movesize; ++ filepos += movesize; ++ } ++ ++ return (len); ++} ++ ++/* ++ * No-Op ++ */ ++int ++zfs_embed(int *start_sector, int needed_sectors) ++{ ++ return (1); ++} ++ ++#endif /* FSYS_ZFS */ +diff -urN grub.patch50/stage2/fsys_zfs.h grub.zfs_solaris/stage2/fsys_zfs.h +--- grub.patch50/stage2/fsys_zfs.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/fsys_zfs.h 2011-10-12 19:58:29.039922403 +0200 +@@ -0,0 +1,205 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++#ifndef _FSYS_ZFS_H ++#define _FSYS_ZFS_H ++ ++#ifdef FSYS_ZFS ++ ++#ifndef FSIMAGE ++typedef unsigned long long uint64_t; ++typedef unsigned int uint32_t; ++typedef unsigned short uint16_t; ++typedef unsigned char uint8_t; ++typedef unsigned char uchar_t; ++ ++#if defined(_LP64) || defined(_I32LPx) ++typedef unsigned long size_t; ++#else ++typedef unsigned int size_t; ++#endif ++#else ++#include "fsi_zfs.h" ++#endif /* !FSIMAGE */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Global Memory addresses to store MOS and DNODE data ++ */ ++#define MOS ((dnode_phys_t *) ZFS_ADDR) ++#define DNODE (MOS+1) /* move sizeof(dnode_phys_t) bytes */ ++#define ZFS_SCRATCH ((char *)(DNODE+1)) ++ ++/* ++ * Verify dnode type. ++ * Can only be used in functions returning non-0 for failure. ++ */ ++#define VERIFY_DN_TYPE(dnp, type) \ ++ if (type && (dnp)->dn_type != type) { \ ++ return (ERR_FSYS_CORRUPT); \ ++ } ++ ++/* ++ * Verify object set type. ++ * Can only be used in functions returning 0 for failure. ++ */ ++#define VERIFY_OS_TYPE(osp, type) \ ++ if (type && (osp)->os_type != type) { \ ++ errnum = ERR_FSYS_CORRUPT; \ ++ return (0); \ ++ } ++ ++#define ZPOOL_PROP_BOOTFS "bootfs" ++ ++/* General macros */ ++#define BSWAP_8(x) ((x) & 0xff) ++#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8)) ++#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16)) ++#define BSWAP_64(x) ((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32)) ++#define P2ROUNDUP(x, align) (-(-(x) & -(align))) ++ ++/* ++ * XXX Match these macro up with real zfs once we have nvlist support so that we ++ * can support large sector disks. ++ */ ++#define UBERBLOCK_SIZE (1ULL << UBERBLOCK_SHIFT) ++#undef offsetof ++#define offsetof(t, m) ((int)&(((t *)0)->m)) ++#define VDEV_UBERBLOCK_SHIFT UBERBLOCK_SHIFT ++#define VDEV_UBERBLOCK_OFFSET(n) \ ++offsetof(vdev_label_t, vl_uberblock[(n) << VDEV_UBERBLOCK_SHIFT]) ++ ++typedef struct uberblock uberblock_t; ++ ++/* XXX Uberblock_phys_t is no longer in the kernel zfs */ ++typedef struct uberblock_phys { ++ uberblock_t ubp_uberblock; ++ char ubp_pad[UBERBLOCK_SIZE - sizeof (uberblock_t) - ++ sizeof (zio_eck_t)]; ++ zio_eck_t ubp_zec; ++} uberblock_phys_t; ++ ++/* ++ * Macros to get fields in a bp or DVA. ++ */ ++#define P2PHASE(x, align) ((x) & ((align) - 1)) ++#define DVA_OFFSET_TO_PHYS_SECTOR(offset) \ ++ ((offset + VDEV_LABEL_START_SIZE) >> SPA_MINBLOCKSHIFT) ++ ++/* ++ * return x rounded down to an align boundary ++ * eg, P2ALIGN(1200, 1024) == 1024 (1*align) ++ * eg, P2ALIGN(1024, 1024) == 1024 (1*align) ++ * eg, P2ALIGN(0x1234, 0x100) == 0x1200 (0x12*align) ++ * eg, P2ALIGN(0x5600, 0x100) == 0x5600 (0x56*align) ++ */ ++#define P2ALIGN(x, align) ((x) & -(align)) ++ ++/* ++ * For nvlist manipulation. (from nvpair.h) ++ */ ++#define NV_ENCODE_NATIVE 0 ++#define NV_ENCODE_XDR 1 ++#define HOST_ENDIAN 1 /* for x86 machine */ ++#define DATA_TYPE_UINT64 8 ++#define DATA_TYPE_STRING 9 ++#define DATA_TYPE_NVLIST 19 ++#define DATA_TYPE_NVLIST_ARRAY 20 ++ ++/* ++ * Decompression Entry - lzjb ++ */ ++#ifndef NBBY ++#define NBBY 8 ++#endif ++ ++typedef int zfs_decomp_func_t(void *s_start, void *d_start, size_t s_len, ++ size_t d_len); ++typedef struct decomp_entry { ++ char *name; ++ zfs_decomp_func_t *decomp_func; ++} decomp_entry_t; ++ ++/* ++ * FAT ZAP data structures ++ */ ++#define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */ ++#define ZAP_HASH_IDX(hash, n) (((n) == 0) ? 0 : ((hash) >> (64 - (n)))) ++#define CHAIN_END 0xffff /* end of the chunk chain */ ++ ++/* ++ * The amount of space within the chunk available for the array is: ++ * chunk size - space for type (1) - space for next pointer (2) ++ */ ++#define ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3) ++ ++#define ZAP_LEAF_HASH_SHIFT(bs) (bs - 5) ++#define ZAP_LEAF_HASH_NUMENTRIES(bs) (1 << ZAP_LEAF_HASH_SHIFT(bs)) ++#define LEAF_HASH(bs, h) \ ++ ((ZAP_LEAF_HASH_NUMENTRIES(bs)-1) & \ ++ ((h) >> (64 - ZAP_LEAF_HASH_SHIFT(bs)-l->l_hdr.lh_prefix_len))) ++ ++/* ++ * The amount of space available for chunks is: ++ * block size shift - hash entry size (2) * number of hash ++ * entries - header space (2*chunksize) ++ */ ++#define ZAP_LEAF_NUMCHUNKS(bs) \ ++ (((1<l_hash + ZAP_LEAF_HASH_NUMENTRIES(bs)))[idx] ++#define ZAP_LEAF_ENTRY(l, bs, idx) (&ZAP_LEAF_CHUNK(l, bs, idx).l_entry) ++ ++extern void fletcher_2_native(const void *, uint64_t, zio_cksum_t *); ++extern void fletcher_2_byteswap(const void *, uint64_t, zio_cksum_t *); ++extern void fletcher_4_native(const void *, uint64_t, zio_cksum_t *); ++extern void fletcher_4_byteswap(const void *, uint64_t, zio_cksum_t *); ++extern void zio_checksum_SHA256(const void *, uint64_t, zio_cksum_t *); ++extern int lzjb_decompress(void *, void *, size_t, size_t); ++ ++#endif /* FSYS_ZFS */ ++ ++#endif /* !_FSYS_ZFS_H */ +diff -urN grub.patch50/stage2/pc_slice.h grub.zfs_solaris/stage2/pc_slice.h +--- grub.patch50/stage2/pc_slice.h 2011-10-12 19:58:28.887921351 +0200 ++++ grub.zfs_solaris/stage2/pc_slice.h 2011-10-12 19:58:29.043921841 +0200 +@@ -111,9 +111,12 @@ + #define PC_SLICE_TYPE_EZD 0x55 + #define PC_SLICE_TYPE_MINIX 0x80 + #define PC_SLICE_TYPE_LINUX_MINIX 0x81 ++#define PC_SLICE_TYPE_SOLARIS 0x82 /* also Linux swap! */ + #define PC_SLICE_TYPE_EXT2FS 0x83 + #define PC_SLICE_TYPE_LINUX_EXTENDED 0x85 + #define PC_SLICE_TYPE_VSTAFS 0x9e ++#define PC_SLICE_TYPE_SOLARIS_BOOT 0xbe /* Solaris boot (fat) */ ++#define PC_SLICE_TYPE_SOLARIS2 0xbf /* new Solaris type */ + #define PC_SLICE_TYPE_DELL_UTIL 0xde + #define PC_SLICE_TYPE_LINUX_RAID 0xfd + +@@ -129,6 +132,7 @@ + || _type == PC_SLICE_TYPE_FAT16_LBA \ + || _type == PC_SLICE_TYPE_FAT32 \ + || _type == PC_SLICE_TYPE_FAT32_LBA \ ++ || _type == PC_SLICE_TYPE_SOLARIS_BOOT \ + || _type == PC_SLICE_TYPE_DELL_UTIL; }) + + #define IS_PC_SLICE_TYPE_EXTENDED(type) \ +@@ -154,6 +158,9 @@ + + #define IS_PC_SLICE_TYPE_BSD(type) IS_PC_SLICE_TYPE_BSD_WITH_FS(type,0) + ++#define IS_PC_SLICE_TYPE_SOLARIS(type) \ ++ (((type) == PC_SLICE_TYPE_SOLARIS) || ((type) == PC_SLICE_TYPE_SOLARIS2)) ++ + /* + * *BSD-style disklabel & partition definitions. + * +@@ -248,4 +255,29 @@ + #define FS_EXT2FS 17 /* Linux Extended 2 file system */ + + ++/* ++ * Solaris LABEL definitions. All definitions are relative to the ++ * current PC_SLICE. ++ */ ++#define SOL_LABEL_LOC 1 ++#define SOL_LABEL_SIZE 512 ++#define SOL_LABEL_MAGIC 0xdabe ++#define SOL_LABEL_MAGIC_OFFSET 0x1fc ++#define SOL_LABEL_NPARTS 0x10 ++ ++#define SOL_PART_OFFSET 0x48 ++ ++#define SOL_LABEL_CHECK_MAG(l_ptr) \ ++ (*((unsigned short *) (((int) l_ptr) + SOL_LABEL_MAGIC_OFFSET)) \ ++ == ((unsigned short) SOL_LABEL_MAGIC )) ++ ++#define SOL_PART_START(l_ptr, p) \ ++ (*((unsigned long *) (((int) l_ptr) + SOL_PART_OFFSET + (p) * 0xc + 4))) ++ ++#define SOL_PART_LENGTH(l_ptr, p) \ ++ (*((unsigned long *) (((int) l_ptr) + SOL_PART_OFFSET + (p) * 0xc + 8))) ++ ++#define SOL_PART_EXISTS(l_ptr, p) (SOL_PART_LENGTH(l_ptr, p) != 0) ++ ++ + #endif /* _PC_SLICE_H */ +diff -urN grub.patch50/stage2/shared.h grub.zfs_solaris/stage2/shared.h +--- grub.patch50/stage2/shared.h 2011-10-12 19:58:28.891921946 +0200 ++++ grub.zfs_solaris/stage2/shared.h 2011-10-12 19:58:29.047921884 +0200 +@@ -44,11 +44,29 @@ + # define RAW_SEG(x) (x) + #endif + ++/* ZFS will use the top 4 Meg of domain memory for scratch */ ++#define ZFS_ADDR RAW_ADDR((mbi.mem_lower << 10) - ZFS_SCRATCH_SIZE) ++#define ZFS_SCRATCH_SIZE 0x400000 ++ ++#ifndef MAXPATHLEN ++#define MAXPATHLEN 1024 ++#endif ++ ++#define MAXNAMELEN 256 ++#define MIN(x, y) ((x) < (y) ? (x) : (y)) ++ ++/* Boot signature related defines for the findroot command */ ++#define BOOTSIGN_DIR "/boot/grub/bootsign" ++#define BOOTSIGN_ARGLEN (MAXNAMELEN + 10) /* (,0,d) */ ++#define BOOTSIGN_LEN (sizeof (BOOTSIGN_DIR) + 1 + BOOTSIGN_ARGLEN) ++#define BOOTSIGN_BACKUP "/etc/bootsign" ++ + /* + * Integer sizes + */ + + #define MAXINT 0x7FFFFFFF ++#define MAXUINT 0xFFFFFFFF + + /* Maximum command line size. Before you blindly increase this value, + see the comment in char_io.c (get_cmdline). */ +@@ -212,6 +230,7 @@ + #define STAGE2_ID_XFS_STAGE1_5 8 + #define STAGE2_ID_ISO9660_STAGE1_5 9 + #define STAGE2_ID_UFS2_STAGE1_5 10 ++#define STAGE2_ID_ZFS_STAGE1_5 12 + + #ifndef STAGE1_5 + # define STAGE2_ID STAGE2_ID_STAGE2 +@@ -236,6 +255,8 @@ + # define STAGE2_ID STAGE2_ID_ISO9660_STAGE1_5 + # elif defined(FSYS_UFS2) + # define STAGE2_ID STAGE2_ID_UFS2_STAGE1_5 ++# elif defined(FSYS_ZFS) ++# define STAGE2_ID STAGE2_ID_ZFS_STAGE1_5 + # else + # error "unknown Stage 2" + # endif +@@ -549,6 +570,9 @@ + ERR_DEV_NEED_INIT, + ERR_NO_DISK_SPACE, + ERR_NUMBER_OVERFLOW, ++ ERR_FILESYSTEM_NOT_FOUND, ++ ERR_NO_BOOTPATH, ++ ERR_NEWER_VERSION, + + MAX_ERR_NUM + } grub_error_t; +@@ -635,6 +659,15 @@ + + extern unsigned long current_drive; + extern unsigned long current_partition; ++extern char current_rootpool[MAXNAMELEN]; ++extern char current_bootfs[MAXNAMELEN]; ++extern unsigned long long current_bootfs_obj; ++extern char current_bootpath[MAXPATHLEN]; ++extern char current_devid[MAXPATHLEN]; ++extern int is_zfs_mount; ++extern unsigned long best_drive; ++extern unsigned long best_part; ++extern int find_best_root; + + extern int fsys_type; + +@@ -889,6 +922,7 @@ + int grub_strcmp (const char *s1, const char *s2); + int grub_strlen (const char *str); + char *grub_strcpy (char *dest, const char *src); ++char *grub_strchr (char *str, char c); + + #ifndef GRUB_UTIL + typedef unsigned long grub_jmp_buf[6]; +diff -urN grub.patch50/stage2/stage2.c grub.zfs_solaris/stage2/stage2.c +--- grub.patch50/stage2/stage2.c 2011-10-12 19:58:28.891921946 +0200 ++++ grub.zfs_solaris/stage2/stage2.c 2011-10-12 19:58:29.047921884 +0200 +@@ -871,6 +871,7 @@ + return pos; + } + ++extern int findroot_func (char *arg, int flags); + + /* This is the starting function in C. */ + void +@@ -961,11 +962,21 @@ + if (! is_opened) + { + is_opened = grub_open (config_file); +- errnum = ERR_NONE; + } ++ /* ++ * we're not going to get very far if we weren't able to ++ * open the config file and this isn't a valid filesystem, ++ * so look for the config file somewhere else ++ */ ++ if (!is_opened && errnum == ERR_FSYS_MOUNT && ++ (findroot_func(config_file, 0) == 0)) { ++ is_opened = grub_open (config_file); ++ } + +- if (! is_opened) ++ if (! is_opened) { ++ errnum = ERR_NONE; + break; ++ } + + /* This is necessary, because the menu must be overrided. */ + reset (); +diff -urN grub.patch50/stage2/zfs-include/dmu.h grub.zfs_solaris/stage2/zfs-include/dmu.h +--- grub.patch50/stage2/zfs-include/dmu.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/dmu.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,120 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_DMU_H ++#define _SYS_DMU_H ++ ++/* ++ * This file describes the interface that the DMU provides for its ++ * consumers. ++ * ++ * The DMU also interacts with the SPA. That interface is described in ++ * dmu_spa.h. ++ */ ++typedef enum dmu_object_type { ++ DMU_OT_NONE, ++ /* general: */ ++ DMU_OT_OBJECT_DIRECTORY, /* ZAP */ ++ DMU_OT_OBJECT_ARRAY, /* UINT64 */ ++ DMU_OT_PACKED_NVLIST, /* UINT8 (XDR by nvlist_pack/unpack) */ ++ DMU_OT_PACKED_NVLIST_SIZE, /* UINT64 */ ++ DMU_OT_BPLIST, /* UINT64 */ ++ DMU_OT_BPLIST_HDR, /* UINT64 */ ++ /* spa: */ ++ DMU_OT_SPACE_MAP_HEADER, /* UINT64 */ ++ DMU_OT_SPACE_MAP, /* UINT64 */ ++ /* zil: */ ++ DMU_OT_INTENT_LOG, /* UINT64 */ ++ /* dmu: */ ++ DMU_OT_DNODE, /* DNODE */ ++ DMU_OT_OBJSET, /* OBJSET */ ++ /* dsl: */ ++ DMU_OT_DSL_DIR, /* UINT64 */ ++ DMU_OT_DSL_DIR_CHILD_MAP, /* ZAP */ ++ DMU_OT_DSL_DS_SNAP_MAP, /* ZAP */ ++ DMU_OT_DSL_PROPS, /* ZAP */ ++ DMU_OT_DSL_DATASET, /* UINT64 */ ++ /* zpl: */ ++ DMU_OT_ZNODE, /* ZNODE */ ++ DMU_OT_OLDACL, /* OLD ACL */ ++ DMU_OT_PLAIN_FILE_CONTENTS, /* UINT8 */ ++ DMU_OT_DIRECTORY_CONTENTS, /* ZAP */ ++ DMU_OT_MASTER_NODE, /* ZAP */ ++ DMU_OT_UNLINKED_SET, /* ZAP */ ++ /* zvol: */ ++ DMU_OT_ZVOL, /* UINT8 */ ++ DMU_OT_ZVOL_PROP, /* ZAP */ ++ /* other; for testing only! */ ++ DMU_OT_PLAIN_OTHER, /* UINT8 */ ++ DMU_OT_UINT64_OTHER, /* UINT64 */ ++ DMU_OT_ZAP_OTHER, /* ZAP */ ++ /* new object types: */ ++ DMU_OT_ERROR_LOG, /* ZAP */ ++ DMU_OT_SPA_HISTORY, /* UINT8 */ ++ DMU_OT_SPA_HISTORY_OFFSETS, /* spa_his_phys_t */ ++ DMU_OT_POOL_PROPS, /* ZAP */ ++ DMU_OT_DSL_PERMS, /* ZAP */ ++ DMU_OT_ACL, /* ACL */ ++ DMU_OT_SYSACL, /* SYSACL */ ++ DMU_OT_FUID, /* FUID table (Packed NVLIST UINT8) */ ++ DMU_OT_FUID_SIZE, /* FUID table size UINT64 */ ++ DMU_OT_NEXT_CLONES, /* ZAP */ ++ DMU_OT_SCRUB_QUEUE, /* ZAP */ ++ DMU_OT_USERGROUP_USED, /* ZAP */ ++ DMU_OT_USERGROUP_QUOTA, /* ZAP */ ++ DMU_OT_USERREFS, /* ZAP */ ++ DMU_OT_DDT_ZAP, /* ZAP */ ++ DMU_OT_DDT_STATS, /* ZAP */ ++ DMU_OT_SA, /* System attr */ ++ DMU_OT_SA_MASTER_NODE, /* ZAP */ ++ DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */ ++ DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */ ++ DMU_OT_NUMTYPES ++} dmu_object_type_t; ++ ++typedef enum dmu_objset_type { ++ DMU_OST_NONE, ++ DMU_OST_META, ++ DMU_OST_ZFS, ++ DMU_OST_ZVOL, ++ DMU_OST_OTHER, /* For testing only! */ ++ DMU_OST_ANY, /* Be careful! */ ++ DMU_OST_NUMTYPES ++} dmu_objset_type_t; ++ ++/* ++ * The names of zap entries in the DIRECTORY_OBJECT of the MOS. ++ */ ++#define DMU_POOL_DIRECTORY_OBJECT 1 ++#define DMU_POOL_CONFIG "config" ++#define DMU_POOL_ROOT_DATASET "root_dataset" ++#define DMU_POOL_SYNC_BPLIST "sync_bplist" ++#define DMU_POOL_ERRLOG_SCRUB "errlog_scrub" ++#define DMU_POOL_ERRLOG_LAST "errlog_last" ++#define DMU_POOL_SPARES "spares" ++#define DMU_POOL_DEFLATE "deflate" ++#define DMU_POOL_HISTORY "history" ++#define DMU_POOL_PROPS "pool_props" ++#define DMU_POOL_L2CACHE "l2cache" ++ ++#endif /* _SYS_DMU_H */ +diff -urN grub.patch50/stage2/zfs-include/dmu_objset.h grub.zfs_solaris/stage2/zfs-include/dmu_objset.h +--- grub.patch50/stage2/zfs-include/dmu_objset.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/dmu_objset.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,38 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_DMU_OBJSET_H ++#define _SYS_DMU_OBJSET_H ++ ++typedef struct objset_phys { ++ dnode_phys_t os_meta_dnode; ++ zil_header_t os_zil_header; ++ uint64_t os_type; ++ uint64_t os_flags; ++ char os_pad[2048 - sizeof (dnode_phys_t)*3 - ++ sizeof (zil_header_t) - sizeof (uint64_t)*2]; ++ dnode_phys_t os_userused_dnode; ++ dnode_phys_t os_groupused_dnode; ++} objset_phys_t; ++ ++#endif /* _SYS_DMU_OBJSET_H */ +diff -urN grub.patch50/stage2/zfs-include/dnode.h grub.zfs_solaris/stage2/zfs-include/dnode.h +--- grub.patch50/stage2/zfs-include/dnode.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/dnode.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,79 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_DNODE_H ++#define _SYS_DNODE_H ++ ++/* ++ * Fixed constants. ++ */ ++#define DNODE_SHIFT 9 /* 512 bytes */ ++#define DN_MIN_INDBLKSHIFT 10 /* 1k */ ++#define DN_MAX_INDBLKSHIFT 14 /* 16k */ ++#define DNODE_BLOCK_SHIFT 14 /* 16k */ ++#define DNODE_CORE_SIZE 64 /* 64 bytes for dnode sans blkptrs */ ++#define DN_MAX_OBJECT_SHIFT 48 /* 256 trillion (zfs_fid_t limit) */ ++#define DN_MAX_OFFSET_SHIFT 64 /* 2^64 bytes in a dnode */ ++ ++/* ++ * Derived constants. ++ */ ++#define DNODE_SIZE (1 << DNODE_SHIFT) ++#define DN_MAX_NBLKPTR ((DNODE_SIZE - DNODE_CORE_SIZE) >> SPA_BLKPTRSHIFT) ++#define DN_MAX_BONUSLEN (DNODE_SIZE - DNODE_CORE_SIZE - (1 << SPA_BLKPTRSHIFT)) ++#define DN_MAX_OBJECT (1ULL << DN_MAX_OBJECT_SHIFT) ++ ++#define DNODES_PER_BLOCK_SHIFT (DNODE_BLOCK_SHIFT - DNODE_SHIFT) ++#define DNODES_PER_BLOCK (1ULL << DNODES_PER_BLOCK_SHIFT) ++#define DNODES_PER_LEVEL_SHIFT (DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT) ++ ++#define DNODE_FLAG_SPILL_BLKPTR (1<<2) ++ ++#define DN_BONUS(dnp) ((void*)((dnp)->dn_bonus + \ ++ (((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t)))) ++ ++typedef struct dnode_phys { ++ uint8_t dn_type; /* dmu_object_type_t */ ++ uint8_t dn_indblkshift; /* ln2(indirect block size) */ ++ uint8_t dn_nlevels; /* 1=dn_blkptr->data blocks */ ++ uint8_t dn_nblkptr; /* length of dn_blkptr */ ++ uint8_t dn_bonustype; /* type of data in bonus buffer */ ++ uint8_t dn_checksum; /* ZIO_CHECKSUM type */ ++ uint8_t dn_compress; /* ZIO_COMPRESS type */ ++ uint8_t dn_flags; /* DNODE_FLAG_* */ ++ uint16_t dn_datablkszsec; /* data block size in 512b sectors */ ++ uint16_t dn_bonuslen; /* length of dn_bonus */ ++ uint8_t dn_pad2[4]; ++ ++ /* accounting is protected by dn_dirty_mtx */ ++ uint64_t dn_maxblkid; /* largest allocated block ID */ ++ uint64_t dn_used; /* bytes (or sectors) of disk space */ ++ ++ uint64_t dn_pad3[4]; ++ ++ blkptr_t dn_blkptr[1]; ++ uint8_t dn_bonus[DN_MAX_BONUSLEN - sizeof (blkptr_t)]; ++ blkptr_t dn_spill; ++} dnode_phys_t; ++ ++#endif /* _SYS_DNODE_H */ +diff -urN grub.patch50/stage2/zfs-include/dsl_dataset.h grub.zfs_solaris/stage2/zfs-include/dsl_dataset.h +--- grub.patch50/stage2/zfs-include/dsl_dataset.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/dsl_dataset.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,55 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_DSL_DATASET_H ++#define _SYS_DSL_DATASET_H ++ ++#pragma ident "%Z%%M% %I% %E% SMI" ++ ++typedef struct dsl_dataset_phys { ++ uint64_t ds_dir_obj; ++ uint64_t ds_prev_snap_obj; ++ uint64_t ds_prev_snap_txg; ++ uint64_t ds_next_snap_obj; ++ uint64_t ds_snapnames_zapobj; /* zap obj of snaps; ==0 for snaps */ ++ uint64_t ds_num_children; /* clone/snap children; ==0 for head */ ++ uint64_t ds_creation_time; /* seconds since 1970 */ ++ uint64_t ds_creation_txg; ++ uint64_t ds_deadlist_obj; ++ uint64_t ds_used_bytes; ++ uint64_t ds_compressed_bytes; ++ uint64_t ds_uncompressed_bytes; ++ uint64_t ds_unique_bytes; /* only relevant to snapshots */ ++ /* ++ * The ds_fsid_guid is a 56-bit ID that can change to avoid ++ * collisions. The ds_guid is a 64-bit ID that will never ++ * change, so there is a small probability that it will collide. ++ */ ++ uint64_t ds_fsid_guid; ++ uint64_t ds_guid; ++ uint64_t ds_flags; ++ blkptr_t ds_bp; ++ uint64_t ds_pad[8]; /* pad out to 320 bytes for good measure */ ++} dsl_dataset_phys_t; ++ ++#endif /* _SYS_DSL_DATASET_H */ +diff -urN grub.patch50/stage2/zfs-include/dsl_dir.h grub.zfs_solaris/stage2/zfs-include/dsl_dir.h +--- grub.patch50/stage2/zfs-include/dsl_dir.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/dsl_dir.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,51 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_DSL_DIR_H ++#define _SYS_DSL_DIR_H ++ ++#pragma ident "%Z%%M% %I% %E% SMI" ++ ++typedef struct dsl_dir_phys { ++ uint64_t dd_creation_time; /* not actually used */ ++ uint64_t dd_head_dataset_obj; ++ uint64_t dd_parent_obj; ++ uint64_t dd_clone_parent_obj; ++ uint64_t dd_child_dir_zapobj; ++ /* ++ * how much space our children are accounting for; for leaf ++ * datasets, == physical space used by fs + snaps ++ */ ++ uint64_t dd_used_bytes; ++ uint64_t dd_compressed_bytes; ++ uint64_t dd_uncompressed_bytes; ++ /* Administrative quota setting */ ++ uint64_t dd_quota; ++ /* Administrative reservation setting */ ++ uint64_t dd_reserved; ++ uint64_t dd_props_zapobj; ++ uint64_t dd_deleg_zapobj; /* dataset permissions */ ++ uint64_t dd_pad[20]; /* pad out to 256 bytes for good measure */ ++} dsl_dir_phys_t; ++ ++#endif /* _SYS_DSL_DIR_H */ +diff -urN grub.patch50/stage2/zfs-include/sa_impl.h grub.zfs_solaris/stage2/zfs-include/sa_impl.h +--- grub.patch50/stage2/zfs-include/sa_impl.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/sa_impl.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,35 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++#ifndef _SYS_SA_IMPL_H ++#define _SYS_SA_IMPL_H ++ ++typedef struct sa_hdr_phys { ++ uint32_t sa_magic; ++ uint16_t sa_layout_info; ++ uint16_t sa_lengths[1]; ++} sa_hdr_phys_t; ++ ++#define SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0) ++#define SA_SIZE_OFFSET 0x8 ++ ++#endif /* _SYS_SA_IMPL_H */ +diff -urN grub.patch50/stage2/zfs-include/spa.h grub.zfs_solaris/stage2/zfs-include/spa.h +--- grub.patch50/stage2/zfs-include/spa.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/spa.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,352 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. ++ */ ++ ++#ifndef _SYS_SPA_H ++#define _SYS_SPA_H ++ ++/* ++ * General-purpose 32-bit and 64-bit bitfield encodings. ++ */ ++#define BF32_DECODE(x, low, len) P2PHASE((x) >> (low), 1U << (len)) ++#define BF64_DECODE(x, low, len) P2PHASE((x) >> (low), 1ULL << (len)) ++#define BF32_ENCODE(x, low, len) (P2PHASE((x), 1U << (len)) << (low)) ++#define BF64_ENCODE(x, low, len) (P2PHASE((x), 1ULL << (len)) << (low)) ++ ++#define BF32_GET(x, low, len) BF32_DECODE(x, low, len) ++#define BF64_GET(x, low, len) BF64_DECODE(x, low, len) ++ ++#define BF32_SET(x, low, len, val) \ ++ ((x) ^= BF32_ENCODE((x >> low) ^ (val), low, len)) ++#define BF64_SET(x, low, len, val) \ ++ ((x) ^= BF64_ENCODE((x >> low) ^ (val), low, len)) ++ ++#define BF32_GET_SB(x, low, len, shift, bias) \ ++ ((BF32_GET(x, low, len) + (bias)) << (shift)) ++#define BF64_GET_SB(x, low, len, shift, bias) \ ++ ((BF64_GET(x, low, len) + (bias)) << (shift)) ++ ++#define BF32_SET_SB(x, low, len, shift, bias, val) \ ++ BF32_SET(x, low, len, ((val) >> (shift)) - (bias)) ++#define BF64_SET_SB(x, low, len, shift, bias, val) \ ++ BF64_SET(x, low, len, ((val) >> (shift)) - (bias)) ++ ++/* ++ * We currently support nine block sizes, from 512 bytes to 128K. ++ * We could go higher, but the benefits are near-zero and the cost ++ * of COWing a giant block to modify one byte would become excessive. ++ */ ++#define SPA_MINBLOCKSHIFT 9 ++#define SPA_MAXBLOCKSHIFT 17 ++#define SPA_MINBLOCKSIZE (1ULL << SPA_MINBLOCKSHIFT) ++#define SPA_MAXBLOCKSIZE (1ULL << SPA_MAXBLOCKSHIFT) ++ ++#define SPA_BLOCKSIZES (SPA_MAXBLOCKSHIFT - SPA_MINBLOCKSHIFT + 1) ++ ++/* ++ * Size of block to hold the configuration data (a packed nvlist) ++ */ ++#define SPA_CONFIG_BLOCKSIZE (1 << 14) ++ ++/* ++ * The DVA size encodings for LSIZE and PSIZE support blocks up to 32MB. ++ * The ASIZE encoding should be at least 64 times larger (6 more bits) ++ * to support up to 4-way RAID-Z mirror mode with worst-case gang block ++ * overhead, three DVAs per bp, plus one more bit in case we do anything ++ * else that expands the ASIZE. ++ */ ++#define SPA_LSIZEBITS 16 /* LSIZE up to 32M (2^16 * 512) */ ++#define SPA_PSIZEBITS 16 /* PSIZE up to 32M (2^16 * 512) */ ++#define SPA_ASIZEBITS 24 /* ASIZE up to 64 times larger */ ++ ++/* ++ * All SPA data is represented by 128-bit data virtual addresses (DVAs). ++ * The members of the dva_t should be considered opaque outside the SPA. ++ */ ++typedef struct dva { ++ uint64_t dva_word[2]; ++} dva_t; ++ ++/* ++ * Each block has a 256-bit checksum -- strong enough for cryptographic hashes. ++ */ ++typedef struct zio_cksum { ++ uint64_t zc_word[4]; ++} zio_cksum_t; ++ ++/* ++ * Each block is described by its DVAs, time of birth, checksum, etc. ++ * The word-by-word, bit-by-bit layout of the blkptr is as follows: ++ * ++ * 64 56 48 40 32 24 16 8 0 ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 0 | vdev1 |ncopy|L| ASIZE | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 1 |G| offset1 | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 2 | vdev2 |ncopy|L| ASIZE | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 3 |G| offset2 | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 4 | vdev3 |ncopy|L| ASIZE | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 5 |G| offset3 | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 6 |BDE|lvl| type | cksum | comp | PSIZE | LSIZE | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 7 | padding | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 8 | padding | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * 9 | physical birth txg | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * a | logical birth txg | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * b | fill count | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * c | checksum[0] | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * d | checksum[1] | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * e | checksum[2] | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * f | checksum[3] | ++ * +-------+-------+-------+-------+-------+-------+-------+-------+ ++ * ++ * Legend: ++ * ++ * vdev virtual device ID ++ * offset offset into virtual device ++ * LSIZE logical size ++ * PSIZE physical size (after compression) ++ * ASIZE allocated size (including RAID-Z parity and gang block headers) ++ * L layout (e.g. standard vs. RAID-Z/mirror hybrid) ++ * ncopy number of copies if RAID-Z, otherwise 1 ++ * cksum checksum function ++ * comp compression function ++ * G gang block indicator ++ * B byteorder (endianness) ++ * D dedup ++ * E encryption ++ * lvl level of indirection ++ * type DMU object type ++ * phys birth txg of block allocation; zero if same as logical birth txg ++ * log. birth transaction group in which the block was logically born ++ * fill count number of non-zero blocks under this bp ++ * checksum[4] 256-bit checksum of the data this bp describes ++ * ++ * Special notes for encryption: ++ * ++ * A single bit is used to indicate if the block is encrypted. This is ++ * sufficient since all blocks in a dataset always share the same encryption ++ * algorithm-keylen-mode. ++ * ++ * When encryption is enabled blk_dva[2] holds the IV. ++ * When encryption is enabled level 0 blocks checksum[2] and checksum[3] hold ++ * the MAC output from the encryption and the normal checksum is truncated ++ * and stored in checksum[0] and checksum[1]. ++ * ++ */ ++#define SPA_BLKPTRSHIFT 7 /* blkptr_t is 128 bytes */ ++#define SPA_DVAS_PER_BP 3 /* Number of DVAs in a bp */ ++ ++typedef struct blkptr { ++ dva_t blk_dva[SPA_DVAS_PER_BP]; /* Data Virtual Addresses */ ++ uint64_t blk_prop; /* size, compression, type, etc */ ++ uint64_t blk_pad[2]; /* Extra space for the future */ ++ uint64_t blk_phys_birth; /* txg when block was allocated */ ++ uint64_t blk_birth; /* transaction group at birth */ ++ uint64_t blk_fill; /* fill count */ ++ zio_cksum_t blk_cksum; /* 256-bit checksum */ ++} blkptr_t; ++ ++/* ++ * DVA layouts. Normally mirror vdevs contain mirrored data, RAID-Z vdevs ++ * contain RAID-Z data, etc. However, for latency-sensitive metadata, ++ * we can use a mirrored layout across the children of a RAID-Z vdev. ++ * This ensures that such metadata can be read in a single I/O. ++ */ ++typedef enum dva_layout { ++ DVA_LAYOUT_STANDARD = 0, ++ DVA_LAYOUT_RAIDZ_MIRROR ++} dva_layout_t; ++ ++/* ++ * Macros to get and set fields in a bp or DVA. ++ */ ++#define DVA_GET_ASIZE(dva) \ ++ BF64_GET_SB((dva)->dva_word[0], 0, 24, SPA_MINBLOCKSHIFT, 0) ++#define DVA_SET_ASIZE(dva, x) \ ++ BF64_SET_SB((dva)->dva_word[0], 0, 24, SPA_MINBLOCKSHIFT, 0, x) ++ ++#define DVA_GET_LAYOUT(dva) BF64_GET((dva)->dva_word[0], 24, 2) ++#define DVA_SET_LAYOUT(dva, x) BF64_SET((dva)->dva_word[0], 24, 2, x) ++ ++#define DVA_GET_COPIES(dva) BF64_GET_SB((dva)->dva_word[0], 26, 6, 0, 1) ++#define DVA_SET_COPIES(dva, x) BF64_SET_SB((dva)->dva_word[0], 26, 6, 0, 1, x) ++ ++#define DVA_MAX_COPIES (1ULL << 6) ++#define DVA_MAX_INFLATION (4ULL) ++ ++#define DVA_GET_VDEV(dva) BF64_GET((dva)->dva_word[0], 32, 32) ++#define DVA_SET_VDEV(dva, x) BF64_SET((dva)->dva_word[0], 32, 32, x) ++ ++#define DVA_GET_OFFSET(dva) \ ++ BF64_GET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0) ++#define DVA_SET_OFFSET(dva, x) \ ++ BF64_SET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0, x) ++ ++#define DVA_GET_GANG(dva) BF64_GET((dva)->dva_word[1], 63, 1) ++#define DVA_SET_GANG(dva, x) BF64_SET((dva)->dva_word[1], 63, 1, x) ++ ++#define DVA_EQUAL(dva1, dva2) \ ++ ((dva1)->dva_word[1] == (dva2)->dva_word[1] && \ ++ (dva1)->dva_word[0] == (dva2)->dva_word[0]) ++ ++#define DVA_IS_VALID(dva) (DVA_GET_ASIZE(dva) != 0) ++ ++#define DVA_VALID_COPIES(dva) \ ++ (DVA_IS_VALID(dva) ? DVA_GET_COPIES(dva) : 0) ++ ++#define BP_GET_LSIZE(bp) \ ++ BF64_GET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1) ++#define BP_SET_LSIZE(bp, x) \ ++ BF64_SET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1, x) ++ ++#define BP_GET_PSIZE(bp) \ ++ BF64_GET_SB((bp)->blk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1) ++#define BP_SET_PSIZE(bp, x) \ ++ BF64_SET_SB((bp)->blk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1, x) ++ ++#define BP_GET_COMPRESS(bp) BF64_GET((bp)->blk_prop, 32, 8) ++#define BP_SET_COMPRESS(bp, x) BF64_SET((bp)->blk_prop, 32, 8, x) ++ ++#define BP_GET_CHECKSUM(bp) BF64_GET((bp)->blk_prop, 40, 8) ++#define BP_SET_CHECKSUM(bp, x) BF64_SET((bp)->blk_prop, 40, 8, x) ++ ++#define BP_GET_TYPE(bp) BF64_GET((bp)->blk_prop, 48, 8) ++#define BP_SET_TYPE(bp, x) BF64_SET((bp)->blk_prop, 48, 8, x) ++ ++#define BP_GET_LEVEL(bp) BF64_GET((bp)->blk_prop, 56, 5) ++#define BP_SET_LEVEL(bp, x) BF64_SET((bp)->blk_prop, 56, 5, x) ++ ++#define BP_GET_CRYPT(bp) BF64_GET((bp)->blk_prop, 61, 1) ++#define BP_SET_CRYPT(bp, x) BF64_SET((bp)->blk_prop, 61, 1, x) ++#define BP_IS_ENCRYPTED(bp) (0 - BP_GET_CRYPT_FLAG(bp)) ++ ++#define BP_GET_DEDUP(bp) BF64_GET((bp)->blk_prop, 62, 1) ++#define BP_SET_DEDUP(bp, x) BF64_SET((bp)->blk_prop, 62, 1, x) ++ ++#define BP_GET_BYTEORDER(bp) (0 - BF64_GET((bp)->blk_prop, 63, 1)) ++#define BP_SET_BYTEORDER(bp, x) BF64_SET((bp)->blk_prop, 63, 1, x) ++ ++#define BP_PHYSICAL_BIRTH(bp) \ ++ ((bp)->blk_phys_birth ? (bp)->blk_phys_birth : (bp)->blk_birth) ++ ++#define BP_SET_BIRTH(bp, logical, physical) \ ++{ \ ++ (bp)->blk_birth = (logical); \ ++ (bp)->blk_phys_birth = ((logical) == (physical) ? 0 : (physical)); \ ++} ++ ++#define BP_GET_UCSIZE(bp) \ ++ ((BP_GET_LEVEL(bp) > 0 || dmu_ot[BP_GET_TYPE(bp)].ot_metadata) ? \ ++ BP_GET_PSIZE(bp) : BP_GET_LSIZE(bp)) ++ ++#define BP_GET_ASIZE(bp) \ ++ (DVA_GET_ASIZE(&(bp)->blk_dva[0]) + \ ++ DVA_GET_ASIZE(&(bp)->blk_dva[1]) + \ ++ (BP_IS_ENCRYPTED(bp) ? 0 : DVA_GET_ASIZE(&(bp)->blk_dva[2]))) ++ ++#define BP_GET_NDVAS(bp) \ ++ (DVA_IS_VALID(&(bp)->blk_dva[0]) + \ ++ DVA_IS_VALID(&(bp)->blk_dva[1]) + \ ++ (BP_IS_ENCRYPTED(bp) ? 0 : DVA_IS_VALID(&(bp)->blk_dva[2]))) ++ ++#define BP_GET_COPIES(bp) \ ++ (DVA_VALID_COPIES(&(bp)->blk_dva[0]) + \ ++ DVA_VALID_COPIES(&(bp)->blk_dva[1]) + \ ++ (BP_IS_ENCRYPTED(bp) ? 0 : DVA_VALID_COPIES(&(bp)->blk_dva[2]))) ++ ++#define BP_COUNT_GANG(bp) \ ++ (DVA_GET_GANG(&(bp)->blk_dva[0]) + \ ++ DVA_GET_GANG(&(bp)->blk_dva[1]) + \ ++ (BP_IS_ENCRYPTED(bp) ? 0 : DVA_GET_GANG(&(bp)->blk_dva[2]))) ++ ++#define BP_EQUAL(bp1, bp2) \ ++ (BP_PHYSICAL_BIRTH(bp1) == BP_PHYSICAL_BIRTH(bp2) && \ ++ DVA_EQUAL(&(bp1)->blk_dva[0], &(bp2)->blk_dva[0]) && \ ++ DVA_EQUAL(&(bp1)->blk_dva[1], &(bp2)->blk_dva[1]) && \ ++ DVA_EQUAL(&(bp1)->blk_dva[2], &(bp2)->blk_dva[2])) ++ ++#define ZIO_CHECKSUM_EQUAL(zc1, zc2) \ ++ (0 == (((zc1).zc_word[0] - (zc2).zc_word[0]) | \ ++ ((zc1).zc_word[1] - (zc2).zc_word[1]) | \ ++ ((zc1).zc_word[2] - (zc2).zc_word[2]) | \ ++ ((zc1).zc_word[3] - (zc2).zc_word[3]))) ++ ++#define ZIO_SET_CHECKSUM(zcp, w0, w1, w2, w3) \ ++{ \ ++ (zcp)->zc_word[0] = w0; \ ++ (zcp)->zc_word[1] = w1; \ ++ (zcp)->zc_word[2] = w2; \ ++ (zcp)->zc_word[3] = w3; \ ++} ++ ++#define BP_IDENTITY(bp) (&(bp)->blk_dva[0]) ++#define BP_IS_GANG(bp) DVA_GET_GANG(BP_IDENTITY(bp)) ++#define BP_IS_HOLE(bp) ((bp)->blk_birth == 0) ++ ++/* BP_IS_RAIDZ(bp) assumes no block compression */ ++#define BP_IS_RAIDZ(bp) (DVA_GET_ASIZE(&(bp)->blk_dva[0]) > \ ++ BP_GET_PSIZE(bp)) ++ ++#define BP_ZERO(bp) \ ++{ \ ++ (bp)->blk_dva[0].dva_word[0] = 0; \ ++ (bp)->blk_dva[0].dva_word[1] = 0; \ ++ (bp)->blk_dva[1].dva_word[0] = 0; \ ++ (bp)->blk_dva[1].dva_word[1] = 0; \ ++ (bp)->blk_dva[2].dva_word[0] = 0; \ ++ (bp)->blk_dva[2].dva_word[1] = 0; \ ++ (bp)->blk_prop = 0; \ ++ (bp)->blk_pad[0] = 0; \ ++ (bp)->blk_pad[1] = 0; \ ++ (bp)->blk_phys_birth = 0; \ ++ (bp)->blk_birth = 0; \ ++ (bp)->blk_fill = 0; \ ++ ZIO_SET_CHECKSUM(&(bp)->blk_cksum, 0, 0, 0, 0); \ ++} ++/* ++ * Note: the byteorder is either 0 or -1, both of which are palindromes. ++ * This simplifies the endianness handling a bit. ++ */ ++#ifdef _BIG_ENDIAN ++#define ZFS_HOST_BYTEORDER (0ULL) ++#else ++#define ZFS_HOST_BYTEORDER (-1ULL) ++#endif ++ ++#define BP_SHOULD_BYTESWAP(bp) (BP_GET_BYTEORDER(bp) != ZFS_HOST_BYTEORDER) ++ ++#define BP_SPRINTF_LEN 360 ++ ++#endif /* _SYS_SPA_H */ +diff -urN grub.patch50/stage2/zfs-include/uberblock_impl.h grub.zfs_solaris/stage2/zfs-include/uberblock_impl.h +--- grub.patch50/stage2/zfs-include/uberblock_impl.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/uberblock_impl.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,51 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_UBERBLOCK_IMPL_H ++#define _SYS_UBERBLOCK_IMPL_H ++ ++#pragma ident "%Z%%M% %I% %E% SMI" ++ ++/* ++ * The uberblock version is incremented whenever an incompatible on-disk ++ * format change is made to the SPA, DMU, or ZAP. ++ * ++ * Note: the first two fields should never be moved. When a storage pool ++ * is opened, the uberblock must be read off the disk before the version ++ * can be checked. If the ub_version field is moved, we may not detect ++ * version mismatch. If the ub_magic field is moved, applications that ++ * expect the magic number in the first word won't work. ++ */ ++#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */ ++#define UBERBLOCK_SHIFT 10 /* up to 1K */ ++ ++struct uberblock { ++ uint64_t ub_magic; /* UBERBLOCK_MAGIC */ ++ uint64_t ub_version; /* ZFS_VERSION */ ++ uint64_t ub_txg; /* txg of last sync */ ++ uint64_t ub_guid_sum; /* sum of all vdev guids */ ++ uint64_t ub_timestamp; /* UTC time of last sync */ ++ blkptr_t ub_rootbp; /* MOS objset_phys_t */ ++}; ++ ++#endif /* _SYS_UBERBLOCK_IMPL_H */ +diff -urN grub.patch50/stage2/zfs-include/vdev_impl.h grub.zfs_solaris/stage2/zfs-include/vdev_impl.h +--- grub.patch50/stage2/zfs-include/vdev_impl.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/vdev_impl.h 2011-10-12 19:58:29.055921310 +0200 +@@ -0,0 +1,59 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_VDEV_IMPL_H ++#define _SYS_VDEV_IMPL_H ++ ++#define VDEV_PAD_SIZE (8 << 10) ++/* 2 padding areas (vl_pad1 and vl_pad2) to skip */ ++#define VDEV_SKIP_SIZE VDEV_PAD_SIZE * 2 ++#define VDEV_PHYS_SIZE (112 << 10) ++#define VDEV_UBERBLOCK_RING (128 << 10) ++ ++typedef struct vdev_phys { ++ char vp_nvlist[VDEV_PHYS_SIZE - sizeof (zio_eck_t)]; ++ zio_eck_t vp_zbt; ++} vdev_phys_t; ++ ++typedef struct vdev_label { ++ char vl_pad1[VDEV_PAD_SIZE]; /* 8K */ ++ char vl_pad2[VDEV_PAD_SIZE]; /* 8K */ ++ vdev_phys_t vl_vdev_phys; /* 112K */ ++ char vl_uberblock[VDEV_UBERBLOCK_RING]; /* 128K */ ++} vdev_label_t; /* 256K total */ ++ ++/* ++ * Size and offset of embedded boot loader region on each label. ++ * The total size of the first two labels plus the boot area is 4MB. ++ */ ++#define VDEV_BOOT_OFFSET (2 * sizeof (vdev_label_t)) ++#define VDEV_BOOT_SIZE (7ULL << 19) /* 3.5M */ ++ ++/* ++ * Size of label regions at the start and end of each leaf device. ++ */ ++#define VDEV_LABEL_START_SIZE (2 * sizeof (vdev_label_t) + VDEV_BOOT_SIZE) ++#define VDEV_LABEL_END_SIZE (2 * sizeof (vdev_label_t)) ++#define VDEV_LABELS 4 ++ ++#endif /* _SYS_VDEV_IMPL_H */ +diff -urN grub.patch50/stage2/zfs-include/zap_impl.h grub.zfs_solaris/stage2/zfs-include/zap_impl.h +--- grub.patch50/stage2/zfs-include/zap_impl.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/zap_impl.h 2011-10-12 19:58:29.059921869 +0200 +@@ -0,0 +1,111 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_ZAP_IMPL_H ++#define _SYS_ZAP_IMPL_H ++ ++#define ZAP_MAGIC 0x2F52AB2ABULL ++ ++#define MZAP_ENT_LEN 64 ++#define MZAP_NAME_LEN (MZAP_ENT_LEN - 8 - 4 - 2) ++#define MZAP_MAX_BLKSHIFT SPA_MAXBLOCKSHIFT ++#define MZAP_MAX_BLKSZ (1 << MZAP_MAX_BLKSHIFT) ++ ++typedef struct mzap_ent_phys { ++ uint64_t mze_value; ++ uint32_t mze_cd; ++ uint16_t mze_pad; /* in case we want to chain them someday */ ++ char mze_name[MZAP_NAME_LEN]; ++} mzap_ent_phys_t; ++ ++typedef struct mzap_phys { ++ uint64_t mz_block_type; /* ZBT_MICRO */ ++ uint64_t mz_salt; ++ uint64_t mz_pad[6]; ++ mzap_ent_phys_t mz_chunk[1]; ++ /* actually variable size depending on block size */ ++} mzap_phys_t; ++ ++/* ++ * The (fat) zap is stored in one object. It is an array of ++ * 1<= 6] [zap_leaf_t] [ptrtbl] ... ++ * ++ */ ++ ++#define ZBT_LEAF ((1ULL << 63) + 0) ++#define ZBT_HEADER ((1ULL << 63) + 1) ++#define ZBT_MICRO ((1ULL << 63) + 3) ++/* any other values are ptrtbl blocks */ ++ ++/* ++ * the embedded pointer table takes up half a block: ++ * block size / entry size (2^3) / 2 ++ */ ++#define ZAP_EMBEDDED_PTRTBL_SHIFT(zap) (FZAP_BLOCK_SHIFT(zap) - 3 - 1) ++ ++/* ++ * The embedded pointer table starts half-way through the block. Since ++ * the pointer table itself is half the block, it starts at (64-bit) ++ * word number (1<zap_f.zap_phys) \ ++ [(idx) + (1<| ++ * |<-- dnode (192) --->|<----------- "bonus" buffer (320) ---------->| ++ * |<---- znode (264) ---->|<---- data (56) ---->| ++ * ++ * At present, we only use this space to store symbolic links. ++ */ ++} znode_phys_t; ++ ++#endif /* _SYS_FS_ZFS_ZNODE_H */ +diff -urN grub.patch50/stage2/zfs-include/zil.h grub.zfs_solaris/stage2/zfs-include/zil.h +--- grub.patch50/stage2/zfs-include/zil.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/zil.h 2011-10-12 19:58:29.059921869 +0200 +@@ -0,0 +1,57 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_ZIL_H ++#define _SYS_ZIL_H ++ ++/* ++ * Intent log format: ++ * ++ * Each objset has its own intent log. The log header (zil_header_t) ++ * for objset N's intent log is kept in the Nth object of the SPA's ++ * intent_log objset. The log header points to a chain of log blocks, ++ * each of which contains log records (i.e., transactions) followed by ++ * a log block trailer (zil_trailer_t). The format of a log record ++ * depends on the record (or transaction) type, but all records begin ++ * with a common structure that defines the type, length, and txg. ++ */ ++ ++/* ++ * Intent log header - this on disk structure holds fields to manage ++ * the log. All fields are 64 bit to easily handle cross architectures. ++ */ ++typedef struct zil_header { ++ uint64_t zh_claim_txg; /* txg in which log blocks were claimed */ ++ uint64_t zh_replay_seq; /* highest replayed sequence number */ ++ blkptr_t zh_log; /* log chain */ ++ uint64_t zh_claim_seq; /* highest claimed sequence number */ ++ uint64_t zh_flags; /* header flags */ ++ uint64_t zh_pad[4]; ++} zil_header_t; ++ ++/* ++ * zh_flags bit settings ++ */ ++#define ZIL_REPLAY_NEEDED 0x1 /* replay needed - internal only */ ++ ++#endif /* _SYS_ZIL_H */ +diff -urN grub.patch50/stage2/zfs-include/zio.h grub.zfs_solaris/stage2/zfs-include/zio.h +--- grub.patch50/stage2/zfs-include/zio.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/zio.h 2011-10-12 19:58:29.059921869 +0200 +@@ -0,0 +1,79 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. ++ */ ++ ++#ifndef _ZIO_H ++#define _ZIO_H ++ ++#define ZEC_MAGIC 0x210da7ab10c7a11ULL /* zio data bloc tail */ ++ ++typedef struct zio_eck { ++ uint64_t zec_magic; /* for validation, endianness */ ++ zio_cksum_t zec_cksum; /* 256-bit checksum */ ++} zio_eck_t; ++ ++/* ++ * Gang block headers are self-checksumming and contain an array ++ * of block pointers. ++ */ ++#define SPA_GANGBLOCKSIZE SPA_MINBLOCKSIZE ++#define SPA_GBH_NBLKPTRS ((SPA_GANGBLOCKSIZE - \ ++ sizeof (zio_eck_t)) / sizeof (blkptr_t)) ++#define SPA_GBH_FILLER ((SPA_GANGBLOCKSIZE - \ ++ sizeof (zio_eck_t) - \ ++ (SPA_GBH_NBLKPTRS * sizeof (blkptr_t))) /\ ++ sizeof (uint64_t)) ++ ++#define ZIO_GET_IOSIZE(zio) \ ++ (BP_IS_GANG((zio)->io_bp) ? \ ++ SPA_GANGBLOCKSIZE : BP_GET_PSIZE((zio)->io_bp)) ++ ++typedef struct zio_gbh { ++ blkptr_t zg_blkptr[SPA_GBH_NBLKPTRS]; ++ uint64_t zg_filler[SPA_GBH_FILLER]; ++ zio_eck_t zg_tail; ++} zio_gbh_phys_t; ++ ++enum zio_checksum { ++ ZIO_CHECKSUM_INHERIT = 0, ++ ZIO_CHECKSUM_ON, ++ ZIO_CHECKSUM_OFF, ++ ZIO_CHECKSUM_LABEL, ++ ZIO_CHECKSUM_GANG_HEADER, ++ ZIO_CHECKSUM_ZILOG, ++ ZIO_CHECKSUM_FLETCHER_2, ++ ZIO_CHECKSUM_FLETCHER_4, ++ ZIO_CHECKSUM_SHA256, ++ ZIO_CHECKSUM_ZILOG2, ++ ZIO_CHECKSUM_SHA256_MAC, ++ ZIO_CHECKSUM_FUNCTIONS ++}; ++ ++enum zio_compress { ++ ZIO_COMPRESS_INHERIT = 0, ++ ZIO_COMPRESS_ON, ++ ZIO_COMPRESS_OFF, ++ ZIO_COMPRESS_LZJB, ++ ZIO_COMPRESS_EMPTY, ++ ZIO_COMPRESS_FUNCTIONS ++}; ++ ++#endif /* _ZIO_H */ +diff -urN grub.patch50/stage2/zfs-include/zio_checksum.h grub.zfs_solaris/stage2/zfs-include/zio_checksum.h +--- grub.patch50/stage2/zfs-include/zio_checksum.h 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs-include/zio_checksum.h 2011-10-12 19:58:29.059921869 +0200 +@@ -0,0 +1,42 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#ifndef _SYS_ZIO_CHECKSUM_H ++#define _SYS_ZIO_CHECKSUM_H ++ ++/* ++ * Signature for checksum functions. ++ */ ++typedef void zio_checksum_t(const void *data, uint64_t size, zio_cksum_t *zcp); ++ ++/* ++ * Information about each checksum function. ++ */ ++typedef struct zio_checksum_info { ++ zio_checksum_t *ci_func[2]; /* checksum function for each byteorder */ ++ int ci_correctable; /* number of correctable bits */ ++ int ci_eck; /* uses zio embedded checksum? */ ++ char *ci_name; /* descriptive name */ ++} zio_checksum_info_t; ++ ++#endif /* _SYS_ZIO_CHECKSUM_H */ +diff -urN grub.patch50/stage2/zfs_fletcher.c grub.zfs_solaris/stage2/zfs_fletcher.c +--- grub.patch50/stage2/zfs_fletcher.c 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs_fletcher.c 2011-10-12 19:58:29.059921869 +0200 +@@ -0,0 +1,95 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#pragma ident "%Z%%M% %I% %E% SMI" ++ ++#include "fsys_zfs.h" ++ ++ ++void ++fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp) ++{ ++ const uint64_t *ip = buf; ++ const uint64_t *ipend = ip + (size / sizeof (uint64_t)); ++ uint64_t a0, b0, a1, b1; ++ ++ for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) { ++ a0 += ip[0]; ++ a1 += ip[1]; ++ b0 += a0; ++ b1 += a1; ++ } ++ ++ ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1); ++} ++ ++void ++fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp) ++{ ++ const uint64_t *ip = buf; ++ const uint64_t *ipend = ip + (size / sizeof (uint64_t)); ++ uint64_t a0, b0, a1, b1; ++ ++ for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) { ++ a0 += BSWAP_64(ip[0]); ++ a1 += BSWAP_64(ip[1]); ++ b0 += a0; ++ b1 += a1; ++ } ++ ++ ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1); ++} ++ ++void ++fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp) ++{ ++ const uint32_t *ip = buf; ++ const uint32_t *ipend = ip + (size / sizeof (uint32_t)); ++ uint64_t a, b, c, d; ++ ++ for (a = b = c = d = 0; ip < ipend; ip++) { ++ a += ip[0]; ++ b += a; ++ c += b; ++ d += c; ++ } ++ ++ ZIO_SET_CHECKSUM(zcp, a, b, c, d); ++} ++ ++void ++fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp) ++{ ++ const uint32_t *ip = buf; ++ const uint32_t *ipend = ip + (size / sizeof (uint32_t)); ++ uint64_t a, b, c, d; ++ ++ for (a = b = c = d = 0; ip < ipend; ip++) { ++ a += BSWAP_32(ip[0]); ++ b += a; ++ c += b; ++ d += c; ++ } ++ ++ ZIO_SET_CHECKSUM(zcp, a, b, c, d); ++} +diff -urN grub.patch50/stage2/zfs_lzjb.c grub.zfs_solaris/stage2/zfs_lzjb.c +--- grub.patch50/stage2/zfs_lzjb.c 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs_lzjb.c 2011-10-12 19:58:29.059921869 +0200 +@@ -0,0 +1,61 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#pragma ident "%Z%%M% %I% %E% SMI" ++ ++#include "fsys_zfs.h" ++ ++#define MATCH_BITS 6 ++#define MATCH_MIN 3 ++#define OFFSET_MASK ((1 << (16 - MATCH_BITS)) - 1) ++ ++ ++/*ARGSUSED*/ ++int ++lzjb_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len) ++{ ++ uchar_t *src = s_start; ++ uchar_t *dst = d_start; ++ uchar_t *d_end = (uchar_t *)d_start + d_len; ++ uchar_t *cpy, copymap; ++ int copymask = 1 << (NBBY - 1); ++ ++ while (dst < d_end) { ++ if ((copymask <<= 1) == (1 << NBBY)) { ++ copymask = 1; ++ copymap = *src++; ++ } ++ if (copymap & copymask) { ++ int mlen = (src[0] >> (NBBY - MATCH_BITS)) + MATCH_MIN; ++ int offset = ((src[0] << NBBY) | src[1]) & OFFSET_MASK; ++ src += 2; ++ if ((cpy = dst - offset) < (uchar_t *)d_start) ++ return (-1); ++ while (--mlen >= 0 && dst < d_end) ++ *dst++ = *cpy++; ++ } else { ++ *dst++ = *src++; ++ } ++ } ++ return (0); ++} +diff -urN grub.patch50/stage2/zfs_sha256.c grub.zfs_solaris/stage2/zfs_sha256.c +--- grub.patch50/stage2/zfs_sha256.c 1970-01-01 01:00:00.000000000 +0100 ++++ grub.zfs_solaris/stage2/zfs_sha256.c 2011-10-12 19:58:29.059921869 +0200 +@@ -0,0 +1,126 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/* ++ * Copyright 2007 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#pragma ident "%Z%%M% %I% %E% SMI" ++ ++#include "fsys_zfs.h" ++ ++/* ++ * SHA-256 checksum, as specified in FIPS 180-2, available at: ++ * http://csrc.nist.gov/cryptval ++ * ++ * This is a very compact implementation of SHA-256. ++ * It is designed to be simple and portable, not to be fast. ++ */ ++ ++/* ++ * The literal definitions according to FIPS180-2 would be: ++ * ++ * Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) ++ * Maj(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) ++ * ++ * We use logical equivalents which require one less op. ++ */ ++#define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) ++#define Maj(x, y, z) (((x) & (y)) ^ ((z) & ((x) ^ (y)))) ++#define Rot32(x, s) (((x) >> s) | ((x) << (32 - s))) ++#define SIGMA0(x) (Rot32(x, 2) ^ Rot32(x, 13) ^ Rot32(x, 22)) ++#define SIGMA1(x) (Rot32(x, 6) ^ Rot32(x, 11) ^ Rot32(x, 25)) ++#define sigma0(x) (Rot32(x, 7) ^ Rot32(x, 18) ^ ((x) >> 3)) ++#define sigma1(x) (Rot32(x, 17) ^ Rot32(x, 19) ^ ((x) >> 10)) ++ ++static const uint32_t SHA256_K[64] = { ++ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, ++ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, ++ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, ++ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, ++ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, ++ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, ++ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, ++ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, ++ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, ++ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, ++ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, ++ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, ++ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, ++ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, ++ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, ++ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ++}; ++ ++static void ++SHA256Transform(uint32_t *H, const uint8_t *cp) ++{ ++ uint32_t a, b, c, d, e, f, g, h, t, T1, T2, W[64]; ++ ++ for (t = 0; t < 16; t++, cp += 4) ++ W[t] = (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | cp[3]; ++ ++ for (t = 16; t < 64; t++) ++ W[t] = sigma1(W[t - 2]) + W[t - 7] + ++ sigma0(W[t - 15]) + W[t - 16]; ++ ++ a = H[0]; b = H[1]; c = H[2]; d = H[3]; ++ e = H[4]; f = H[5]; g = H[6]; h = H[7]; ++ ++ for (t = 0; t < 64; t++) { ++ T1 = h + SIGMA1(e) + Ch(e, f, g) + SHA256_K[t] + W[t]; ++ T2 = SIGMA0(a) + Maj(a, b, c); ++ h = g; g = f; f = e; e = d + T1; ++ d = c; c = b; b = a; a = T1 + T2; ++ } ++ ++ H[0] += a; H[1] += b; H[2] += c; H[3] += d; ++ H[4] += e; H[5] += f; H[6] += g; H[7] += h; ++} ++ ++void ++zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp) ++{ ++ uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, ++ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; ++ uint8_t pad[128]; ++ int padsize = size & 63; ++ int i; ++ ++ for (i = 0; i < size - padsize; i += 64) ++ SHA256Transform(H, (uint8_t *)buf + i); ++ ++ for (i = 0; i < padsize; i++) ++ pad[i] = ((uint8_t *)buf)[i]; ++ ++ for (pad[padsize++] = 0x80; (padsize & 63) != 56; padsize++) ++ pad[padsize] = 0; ++ ++ for (i = 0; i < 8; i++) ++ pad[padsize++] = (size << 3) >> (56 - 8 * i); ++ ++ for (i = 0; i < padsize; i += 64) ++ SHA256Transform(H, pad + i); ++ ++ ZIO_SET_CHECKSUM(zcp, ++ (uint64_t)H[0] << 32 | H[1], ++ (uint64_t)H[2] << 32 | H[3], ++ (uint64_t)H[4] << 32 | H[5], ++ (uint64_t)H[6] << 32 | H[7]); ++} diff -r 4b0907c6a08c stubdom/grub/Makefile --- a/stubdom/grub/Makefile Tue Oct 11 12:02:58 2011 +0100 +++ b/stubdom/grub/Makefile Wed Oct 12 20:06:15 2011 +0200 @@ -54,6 +54,9 @@ STAGE2_SOURCES+=fsys_xfs.c CPPFLAGS += -DFSYS_XFS=1 +STAGE2_SOURCES+=fsys_zfs.c zfs_fletcher.c zfs_lzjb.c zfs_sha256.c +CPPFLAGS += -DFSYS_ZFS=1 + STAGE2_SOURCES:=$(addprefix stage2/,$(STAGE2_SOURCES)) NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES)) --zhXaljGHf11kAtnf Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel --zhXaljGHf11kAtnf--