xref: /onnv-gate/usr/src/cmd/boot/installgrub/pcfs_glue.c (revision 12947:f5f96e09bf49)
1*12947SEnrico.Perla@Sun.COM /*
2*12947SEnrico.Perla@Sun.COM  * CDDL HEADER START
3*12947SEnrico.Perla@Sun.COM  *
4*12947SEnrico.Perla@Sun.COM  * The contents of this file are subject to the terms of the
5*12947SEnrico.Perla@Sun.COM  * Common Development and Distribution License (the "License").
6*12947SEnrico.Perla@Sun.COM  * You may not use this file except in compliance with the License.
7*12947SEnrico.Perla@Sun.COM  *
8*12947SEnrico.Perla@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12947SEnrico.Perla@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*12947SEnrico.Perla@Sun.COM  * See the License for the specific language governing permissions
11*12947SEnrico.Perla@Sun.COM  * and limitations under the License.
12*12947SEnrico.Perla@Sun.COM  *
13*12947SEnrico.Perla@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*12947SEnrico.Perla@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12947SEnrico.Perla@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*12947SEnrico.Perla@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*12947SEnrico.Perla@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12947SEnrico.Perla@Sun.COM  *
19*12947SEnrico.Perla@Sun.COM  * CDDL HEADER END
20*12947SEnrico.Perla@Sun.COM  */
21*12947SEnrico.Perla@Sun.COM /*
22*12947SEnrico.Perla@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23*12947SEnrico.Perla@Sun.COM  */
24*12947SEnrico.Perla@Sun.COM 
25*12947SEnrico.Perla@Sun.COM #include <stdio.h>
26*12947SEnrico.Perla@Sun.COM #include <stdlib.h>
27*12947SEnrico.Perla@Sun.COM #include <unistd.h>
28*12947SEnrico.Perla@Sun.COM #include <sys/param.h>
29*12947SEnrico.Perla@Sun.COM #include <sys/bootvfs.h>
30*12947SEnrico.Perla@Sun.COM #include <sys/filep.h>
31*12947SEnrico.Perla@Sun.COM 
32*12947SEnrico.Perla@Sun.COM #include <libintl.h>
33*12947SEnrico.Perla@Sun.COM #include <locale.h>
34*12947SEnrico.Perla@Sun.COM #include "message.h"
35*12947SEnrico.Perla@Sun.COM 
36*12947SEnrico.Perla@Sun.COM /*
37*12947SEnrico.Perla@Sun.COM  * This file is glue layer to pcfs module in usr/src/common/fs/pcfs.c.
38*12947SEnrico.Perla@Sun.COM  * It's main functionality is to get the stage file blocklist. It's
39*12947SEnrico.Perla@Sun.COM  * used for installing grub on a Solaris boot partition.
40*12947SEnrico.Perla@Sun.COM  */
41*12947SEnrico.Perla@Sun.COM extern struct boot_fs_ops bpcfs_ops;
42*12947SEnrico.Perla@Sun.COM struct boot_fs_ops *bfs_ops;
43*12947SEnrico.Perla@Sun.COM struct boot_fs_ops *bfs_tab[] = {&bpcfs_ops, NULL};
44*12947SEnrico.Perla@Sun.COM static int dev_fd;
45*12947SEnrico.Perla@Sun.COM int bootrd_debug = 0;
46*12947SEnrico.Perla@Sun.COM 
47*12947SEnrico.Perla@Sun.COM #define	DEV_BSIZE	512
48*12947SEnrico.Perla@Sun.COM #define	MAX_CHUNK	64
49*12947SEnrico.Perla@Sun.COM 
50*12947SEnrico.Perla@Sun.COM static unsigned int *blocklist;
51*12947SEnrico.Perla@Sun.COM 
52*12947SEnrico.Perla@Sun.COM /* diskread_callback is set in filesytem module (pcfs.c) */
53*12947SEnrico.Perla@Sun.COM int (*diskread_callback)(int, int);
54*12947SEnrico.Perla@Sun.COM int (*fileread_callback)(int, int);
55*12947SEnrico.Perla@Sun.COM 
56*12947SEnrico.Perla@Sun.COM static int
add_stage2_block(int blocknum,int nblk)57*12947SEnrico.Perla@Sun.COM add_stage2_block(int blocknum, int nblk)
58*12947SEnrico.Perla@Sun.COM {
59*12947SEnrico.Perla@Sun.COM 	static int i = -2;
60*12947SEnrico.Perla@Sun.COM 
61*12947SEnrico.Perla@Sun.COM 	if (i >= 0 && (blocklist[i] + blocklist[i + 1] == blocknum)) {
62*12947SEnrico.Perla@Sun.COM 		blocklist[i + 1] += nblk;
63*12947SEnrico.Perla@Sun.COM 		return (0);
64*12947SEnrico.Perla@Sun.COM 	}
65*12947SEnrico.Perla@Sun.COM 
66*12947SEnrico.Perla@Sun.COM 	i += 2;
67*12947SEnrico.Perla@Sun.COM 	if (i >= DEV_BSIZE / 8) {
68*12947SEnrico.Perla@Sun.COM 		fprintf(stderr, PCFS_FRAGMENTED);
69*12947SEnrico.Perla@Sun.COM 		exit(-1);
70*12947SEnrico.Perla@Sun.COM 	}
71*12947SEnrico.Perla@Sun.COM 	blocklist[i] = blocknum;
72*12947SEnrico.Perla@Sun.COM 	blocklist[i + 1] = nblk;
73*12947SEnrico.Perla@Sun.COM 	return (0);
74*12947SEnrico.Perla@Sun.COM }
75*12947SEnrico.Perla@Sun.COM 
76*12947SEnrico.Perla@Sun.COM /*
77*12947SEnrico.Perla@Sun.COM  * This one reads the ramdisk. If fi_memp is set, we copy the
78*12947SEnrico.Perla@Sun.COM  * ramdisk content to the designated buffer. Otherwise, we
79*12947SEnrico.Perla@Sun.COM  * do a "cached" read (set fi_memp to the actual ramdisk buffer).
80*12947SEnrico.Perla@Sun.COM  */
81*12947SEnrico.Perla@Sun.COM int
diskread(fileid_t * filep)82*12947SEnrico.Perla@Sun.COM diskread(fileid_t *filep)
83*12947SEnrico.Perla@Sun.COM {
84*12947SEnrico.Perla@Sun.COM 	int ret;
85*12947SEnrico.Perla@Sun.COM 	uint_t blocknum, diskloc;
86*12947SEnrico.Perla@Sun.COM 
87*12947SEnrico.Perla@Sun.COM 	blocknum = filep->fi_blocknum;
88*12947SEnrico.Perla@Sun.COM 
89*12947SEnrico.Perla@Sun.COM 	if (diskread_callback) {
90*12947SEnrico.Perla@Sun.COM 		diskread_callback(blocknum, filep->fi_count / DEV_BSIZE);
91*12947SEnrico.Perla@Sun.COM 		return (0);
92*12947SEnrico.Perla@Sun.COM 	}
93*12947SEnrico.Perla@Sun.COM 
94*12947SEnrico.Perla@Sun.COM 	diskloc = blocknum * DEV_BSIZE;
95*12947SEnrico.Perla@Sun.COM 	if (filep->fi_memp == NULL) {
96*12947SEnrico.Perla@Sun.COM 		filep->fi_memp = malloc(filep->fi_count);
97*12947SEnrico.Perla@Sun.COM 	}
98*12947SEnrico.Perla@Sun.COM 	if (filep->fi_memp == NULL) {
99*12947SEnrico.Perla@Sun.COM 		fprintf(stderr, OUT_OF_MEMORY);
100*12947SEnrico.Perla@Sun.COM 		return (-1);
101*12947SEnrico.Perla@Sun.COM 	}
102*12947SEnrico.Perla@Sun.COM 
103*12947SEnrico.Perla@Sun.COM 	ret = pread(dev_fd, filep->fi_memp, filep->fi_count, diskloc);
104*12947SEnrico.Perla@Sun.COM 	if (ret < 0)
105*12947SEnrico.Perla@Sun.COM 		perror("diskread: pread");
106*12947SEnrico.Perla@Sun.COM 	return (ret >= 0 ? 0 : -1);
107*12947SEnrico.Perla@Sun.COM }
108*12947SEnrico.Perla@Sun.COM 
109*12947SEnrico.Perla@Sun.COM void *
bkmem_alloc(size_t s)110*12947SEnrico.Perla@Sun.COM bkmem_alloc(size_t s)
111*12947SEnrico.Perla@Sun.COM {
112*12947SEnrico.Perla@Sun.COM 	return (malloc(s));
113*12947SEnrico.Perla@Sun.COM }
114*12947SEnrico.Perla@Sun.COM 
115*12947SEnrico.Perla@Sun.COM /*ARGSUSED*/
116*12947SEnrico.Perla@Sun.COM void
bkmem_free(void * p,size_t s)117*12947SEnrico.Perla@Sun.COM bkmem_free(void *p, size_t s)
118*12947SEnrico.Perla@Sun.COM {
119*12947SEnrico.Perla@Sun.COM 	free(p);
120*12947SEnrico.Perla@Sun.COM }
121*12947SEnrico.Perla@Sun.COM 
122*12947SEnrico.Perla@Sun.COM static int
mountroot(char * name)123*12947SEnrico.Perla@Sun.COM mountroot(char *name)
124*12947SEnrico.Perla@Sun.COM {
125*12947SEnrico.Perla@Sun.COM 	int i;
126*12947SEnrico.Perla@Sun.COM 
127*12947SEnrico.Perla@Sun.COM 	/* try ops in bfs_tab and return the first successful one */
128*12947SEnrico.Perla@Sun.COM 	for (i = 0; bfs_tab[i] != NULL; i++) {
129*12947SEnrico.Perla@Sun.COM 		bfs_ops = bfs_tab[i];
130*12947SEnrico.Perla@Sun.COM 		if (BRD_MOUNTROOT(bfs_ops, name) == 0)
131*12947SEnrico.Perla@Sun.COM 			return (0);
132*12947SEnrico.Perla@Sun.COM 	}
133*12947SEnrico.Perla@Sun.COM 	return (-1);
134*12947SEnrico.Perla@Sun.COM }
135*12947SEnrico.Perla@Sun.COM 
136*12947SEnrico.Perla@Sun.COM static int
unmountroot()137*12947SEnrico.Perla@Sun.COM unmountroot()
138*12947SEnrico.Perla@Sun.COM {
139*12947SEnrico.Perla@Sun.COM 	return (BRD_UNMOUNTROOT(bfs_ops));
140*12947SEnrico.Perla@Sun.COM }
141*12947SEnrico.Perla@Sun.COM 
142*12947SEnrico.Perla@Sun.COM static int
pcfs_glue_open(const char * filename,int flags)143*12947SEnrico.Perla@Sun.COM pcfs_glue_open(const char *filename, int flags)
144*12947SEnrico.Perla@Sun.COM {
145*12947SEnrico.Perla@Sun.COM 	return (BRD_OPEN(bfs_ops, (char *)filename, flags));
146*12947SEnrico.Perla@Sun.COM }
147*12947SEnrico.Perla@Sun.COM 
148*12947SEnrico.Perla@Sun.COM static int
pcfs_glue_close(int fd)149*12947SEnrico.Perla@Sun.COM pcfs_glue_close(int fd)
150*12947SEnrico.Perla@Sun.COM {
151*12947SEnrico.Perla@Sun.COM 	return (BRD_CLOSE(bfs_ops, fd));
152*12947SEnrico.Perla@Sun.COM }
153*12947SEnrico.Perla@Sun.COM 
154*12947SEnrico.Perla@Sun.COM static ssize_t
pcfs_glue_read(int fd,void * buf,size_t size)155*12947SEnrico.Perla@Sun.COM pcfs_glue_read(int fd, void *buf, size_t size)
156*12947SEnrico.Perla@Sun.COM {
157*12947SEnrico.Perla@Sun.COM 	return (BRD_READ(bfs_ops, fd, buf, size));
158*12947SEnrico.Perla@Sun.COM }
159*12947SEnrico.Perla@Sun.COM 
160*12947SEnrico.Perla@Sun.COM static off_t
pcfs_glue_lseek(int fd,off_t addr,int whence)161*12947SEnrico.Perla@Sun.COM pcfs_glue_lseek(int fd, off_t addr, int whence)
162*12947SEnrico.Perla@Sun.COM {
163*12947SEnrico.Perla@Sun.COM 	return (BRD_SEEK(bfs_ops, fd, addr, whence));
164*12947SEnrico.Perla@Sun.COM }
165*12947SEnrico.Perla@Sun.COM 
166*12947SEnrico.Perla@Sun.COM /*
167*12947SEnrico.Perla@Sun.COM  * Get the blocklist for stage2
168*12947SEnrico.Perla@Sun.COM  */
169*12947SEnrico.Perla@Sun.COM int
read_stage2_blocklist(int device_fd,unsigned int * blkbuf)170*12947SEnrico.Perla@Sun.COM read_stage2_blocklist(int device_fd, unsigned int *blkbuf)
171*12947SEnrico.Perla@Sun.COM {
172*12947SEnrico.Perla@Sun.COM 	int i, fd, stage2_block;
173*12947SEnrico.Perla@Sun.COM 	char buf[DEV_BSIZE];
174*12947SEnrico.Perla@Sun.COM 	ssize_t size;
175*12947SEnrico.Perla@Sun.COM 
176*12947SEnrico.Perla@Sun.COM 	dev_fd = device_fd;
177*12947SEnrico.Perla@Sun.COM 	if (mountroot("dummy") != 0) {
178*12947SEnrico.Perla@Sun.COM 		fprintf(stderr, MOUNT_FAIL_PCFS);
179*12947SEnrico.Perla@Sun.COM 		return (-1);
180*12947SEnrico.Perla@Sun.COM 	}
181*12947SEnrico.Perla@Sun.COM 
182*12947SEnrico.Perla@Sun.COM 	if ((fd = pcfs_glue_open("/boot/grub/stage2", 0)) == -1) {
183*12947SEnrico.Perla@Sun.COM 		fprintf(stderr, OPEN_FAIL_PCFS);
184*12947SEnrico.Perla@Sun.COM 		return (-1);
185*12947SEnrico.Perla@Sun.COM 	}
186*12947SEnrico.Perla@Sun.COM 
187*12947SEnrico.Perla@Sun.COM 	if (bootrd_debug)
188*12947SEnrico.Perla@Sun.COM 		(void) printf("start reading stage2:\n");
189*12947SEnrico.Perla@Sun.COM 	stage2_block = 0;
190*12947SEnrico.Perla@Sun.COM 	blocklist = blkbuf;
191*12947SEnrico.Perla@Sun.COM 	fileread_callback = add_stage2_block;
192*12947SEnrico.Perla@Sun.COM 	for (;;) {
193*12947SEnrico.Perla@Sun.COM 		size = pcfs_glue_read(fd, buf, DEV_BSIZE);
194*12947SEnrico.Perla@Sun.COM 		if (size != DEV_BSIZE)
195*12947SEnrico.Perla@Sun.COM 			break;
196*12947SEnrico.Perla@Sun.COM 		stage2_block++;
197*12947SEnrico.Perla@Sun.COM 	}
198*12947SEnrico.Perla@Sun.COM 	fileread_callback = NULL;
199*12947SEnrico.Perla@Sun.COM 	(void) pcfs_glue_close(fd);
200*12947SEnrico.Perla@Sun.COM 
201*12947SEnrico.Perla@Sun.COM 	if (bootrd_debug) {
202*12947SEnrico.Perla@Sun.COM 		(void) printf("last block size = %d\n", size);
203*12947SEnrico.Perla@Sun.COM 		for (i = 0; blocklist[i] != 0; i += 2) {
204*12947SEnrico.Perla@Sun.COM 			(void) printf("sectors: %d-%d\n",
205*12947SEnrico.Perla@Sun.COM 			    blocklist[i],
206*12947SEnrico.Perla@Sun.COM 			    blocklist[i] + blocklist[i + 1] - 1);
207*12947SEnrico.Perla@Sun.COM 		}
208*12947SEnrico.Perla@Sun.COM 		(void) printf("total blocks in stage 2: %d\n", stage2_block);
209*12947SEnrico.Perla@Sun.COM 	}
210*12947SEnrico.Perla@Sun.COM 
211*12947SEnrico.Perla@Sun.COM 	(void) unmountroot();
212*12947SEnrico.Perla@Sun.COM 	return (0);
213*12947SEnrico.Perla@Sun.COM }
214