1 /*
2  *  GRUB  --  GRand Unified Bootloader
3  *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
17  */
18 /*
19  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
20  * Use is subject to license terms.
21  */
22 
23 #ifdef	FSYS_ZFS
24 
25 #include <xenfsimage_grub.h>
26 #include <fsimage_priv.h>
27 #include <stdio.h>
28 #include <inttypes.h>
29 #include "mb_info.h"
30 
31 
32 #undef filemax
33 #undef filepos
34 #undef errnum
35 
36 
37 #define	MAXNAMELEN	256
38 #define	MAXPATHLEN	1024
39 
40 /**** START FROM disk_io.c ****/
41 char current_rootpool[MAXNAMELEN];
42 char current_bootfs[MAXNAMELEN];
43 uint64_t current_bootfs_obj;
44 char current_bootpath[MAXPATHLEN];
45 char current_devid[MAXPATHLEN];
46 int is_zfs_mount;
47 unsigned long best_drive;
48 unsigned long best_part;
49 int find_best_root;
50 unsigned long part_length;
51 /**** END FROM disk_io.c ****/
52 
53 uint64_t filemax;
54 uint64_t filepos;
55 
56 struct multiboot_info mbi;
57 fsi_file_t *zfs_ffi;
58 int errnum;
59 char *bootstring = NULL;
60 
61 extern int zfs_mount(void);
62 extern int zfs_open(char *filename);
63 extern int zfs_read(char *buf, int len);
64 
65 #define	ZFS_SCRATCH_SIZE	0x400000
66 #define	FSI_MOS_SHIFT	10
67 #define	FSI_MOS_MASK	((1 << FSI_MOS_SHIFT) - 1)
68 unsigned char fsi_mos_buf[ZFS_SCRATCH_SIZE + FSI_MOS_MASK + 1];
69 
70 #define	FSI_MOS_ALIGN(addr)	(((uintptr_t)addr + FSI_MOS_MASK) & \
71 				~FSI_MOS_MASK)
72 #define	FSI_MOS(buf)  		((FSI_MOS_ALIGN(buf) + \
73 				ZFS_SCRATCH_SIZE - 0x100000) >> FSI_MOS_SHIFT)
74 
75 static int
fsi_zfs_mount(fsi_file_t * ffi,const char * options)76 fsi_zfs_mount(fsi_file_t *ffi, const char *options)
77 {
78 	zfs_ffi = ffi;
79 	mbi.mem_upper = FSI_MOS(fsi_mos_buf);
80 
81 	/* If an boot filesystem is passed in, set it to current_bootfs */
82 	if (options != NULL) {
83 		if (strlen(options) < MAXNAMELEN) {
84 			strcpy(current_bootfs, options);
85 		}
86 	}
87 
88 	return (zfs_mount());
89 }
90 
91 static int
fsi_zfs_open(fsi_file_t * ffi,char * filename)92 fsi_zfs_open(fsi_file_t *ffi, char *filename)
93 {
94 	char *fsi_bootstring;
95 	uint64_t *fmax;
96 	uint64_t *fpos;
97 	int rc;
98 
99 	zfs_ffi = ffi;
100 	fmax = fsig_filemax(ffi);
101 	fpos = fsig_filepos(ffi);
102 
103 	rc = zfs_open(filename);
104 	if (rc != 1) {
105 		return (rc);
106 	}
107 
108 	*fmax = filemax;
109 	*fpos = filepos;
110 
111 	if (bootstring == NULL) {
112 		rc = asprintf(&bootstring,
113 			      "zfs-bootfs=%s/%"PRIu64",bootpath='%s'",
114 			      current_rootpool, current_bootfs_obj,
115 			      current_bootpath);
116 		if (rc == -1) {
117 			return (rc);
118 		}
119 		fsi_bootstring = fsi_bootstring_alloc(ffi->ff_fsi,
120 		    strlen(bootstring) + 1);
121 		strcpy(fsi_bootstring, bootstring);
122 	}
123 
124 	return (rc);
125 }
126 
127 static int
fsi_zfs_read(fsi_file_t * ffi,char * buf,int len)128 fsi_zfs_read(fsi_file_t *ffi, char *buf, int len)
129 {
130 	uint64_t *fpos;
131 	int rc;
132 
133 	zfs_ffi = ffi;
134 	fpos = fsig_filepos(ffi);
135 	filepos = *fpos;
136 	rc = zfs_read(buf, len);
137 	*fpos = filepos;
138 
139 	return (rc);
140 }
141 
142 
143 fsi_plugin_ops_t *
fsi_init_plugin(int version,fsi_plugin_t * fp,const char ** name)144 fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
145 {
146        static fsig_plugin_ops_t ops = {
147                FSIMAGE_PLUGIN_VERSION,
148                .fpo_mount = fsi_zfs_mount,
149                .fpo_dir = fsi_zfs_open,
150                .fpo_read = fsi_zfs_read,
151        };
152 
153        *name = "zfs";
154        return (fsig_init(fp, &ops));
155 }
156 
157 #endif /* FSYS_ZFS */
158