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