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