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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include <sys/param.h> 30 #include <sys/bootvfs.h> 31 #include <sys/filep.h> 32 33 #include <libintl.h> 34 #include <locale.h> 35 #include "message.h" 36 37 /* 38 * This file is glue layer to pcfs module in usr/src/common/fs/pcfs.c. 39 * It's main functionality is to get the stage file blocklist. It's 40 * used for installing grub on floppy and Solaris boot partition. 41 */ 42 extern struct boot_fs_ops bpcfs_ops; 43 struct boot_fs_ops *bfs_ops; 44 struct boot_fs_ops *bfs_tab[] = {&bpcfs_ops, NULL}; 45 static int dev_fd; 46 int bootrd_debug = 0; 47 48 #define DEV_BSIZE 512 49 #define MAX_CHUNK 64 50 51 static unsigned int *blocklist; 52 53 /* diskread_callback is set in filesytem module (pcfs.c) */ 54 int (*diskread_callback)(int, int); 55 int (*fileread_callback)(int, int); 56 57 static int 58 add_stage2_block(int blocknum, int nblk) 59 { 60 static int i = -2; 61 62 if (i >= 0 && (blocklist[i] + blocklist[i + 1] == blocknum)) { 63 blocklist[i + 1] += nblk; 64 return (0); 65 } 66 67 i += 2; 68 if (i >= DEV_BSIZE / 8) { 69 fprintf(stderr, PCFS_FRAGMENTED); 70 exit(-1); 71 } 72 blocklist[i] = blocknum; 73 blocklist[i + 1] = nblk; 74 return (0); 75 } 76 77 /* 78 * This one reads the ramdisk. If fi_memp is set, we copy the 79 * ramdisk content to the designated buffer. Otherwise, we 80 * do a "cached" read (set fi_memp to the actual ramdisk buffer). 81 */ 82 int 83 diskread(fileid_t *filep) 84 { 85 int ret; 86 uint_t blocknum, diskloc; 87 88 blocknum = filep->fi_blocknum; 89 90 if (diskread_callback) { 91 diskread_callback(blocknum, filep->fi_count / DEV_BSIZE); 92 return (0); 93 } 94 95 diskloc = blocknum * DEV_BSIZE; 96 if (filep->fi_memp == NULL) { 97 filep->fi_memp = malloc(filep->fi_count); 98 } 99 if (filep->fi_memp == NULL) { 100 fprintf(stderr, OUT_OF_MEMORY); 101 return (-1); 102 } 103 104 ret = pread(dev_fd, filep->fi_memp, filep->fi_count, diskloc); 105 if (ret < 0) 106 perror("diskread: pread"); 107 return (ret >= 0 ? 0 : -1); 108 } 109 110 void * 111 bkmem_alloc(size_t s) 112 { 113 return (malloc(s)); 114 } 115 116 /*ARGSUSED*/ 117 void 118 bkmem_free(void *p, size_t s) 119 { 120 free(p); 121 } 122 123 static int 124 mountroot(char *name) 125 { 126 int i; 127 128 /* try ops in bfs_tab and return the first successful one */ 129 for (i = 0; bfs_tab[i] != NULL; i++) { 130 bfs_ops = bfs_tab[i]; 131 if (BRD_MOUNTROOT(bfs_ops, name) == 0) 132 return (0); 133 } 134 return (-1); 135 } 136 137 static int 138 unmountroot() 139 { 140 return (BRD_UNMOUNTROOT(bfs_ops)); 141 } 142 143 static int 144 floppy_open(const char *filename, int flags) 145 { 146 return (BRD_OPEN(bfs_ops, (char *)filename, flags)); 147 } 148 149 static int 150 floppy_close(int fd) 151 { 152 return (BRD_CLOSE(bfs_ops, fd)); 153 } 154 155 static ssize_t 156 floppy_read(int fd, void *buf, size_t size) 157 { 158 return (BRD_READ(bfs_ops, fd, buf, size)); 159 } 160 161 static off_t 162 floppy_lseek(int fd, off_t addr, int whence) 163 { 164 return (BRD_SEEK(bfs_ops, fd, addr, whence)); 165 } 166 167 /* 168 * Get the blocklist for stage2 169 */ 170 int 171 read_stage2_blocklist(int device_fd, unsigned int *blkbuf) 172 { 173 int i, fd, stage2_block; 174 char buf[DEV_BSIZE]; 175 ssize_t size; 176 177 dev_fd = device_fd; 178 if (mountroot("dummy") != 0) { 179 fprintf(stderr, MOUNT_FAIL_PCFS); 180 return (-1); 181 } 182 183 if ((fd = floppy_open("/boot/grub/stage2", 0)) == -1) { 184 fprintf(stderr, OPEN_FAIL_PCFS); 185 return (-1); 186 } 187 188 if (bootrd_debug) 189 (void) printf("start reading stage2:\n"); 190 stage2_block = 0; 191 blocklist = blkbuf; 192 fileread_callback = add_stage2_block; 193 for (;;) { 194 size = floppy_read(fd, buf, DEV_BSIZE); 195 if (size != DEV_BSIZE) 196 break; 197 stage2_block++; 198 } 199 fileread_callback = NULL; 200 (void) floppy_close(fd); 201 202 if (bootrd_debug) { 203 (void) printf("last block size = %d\n", size); 204 for (i = 0; blocklist[i] != 0; i += 2) { 205 (void) printf("sectors: %d-%d\n", 206 blocklist[i], 207 blocklist[i] + blocklist[i + 1] - 1); 208 } 209 (void) printf("total blocks in stage 2: %d\n", stage2_block); 210 } 211 212 (void) unmountroot(); 213 return (0); 214 } 215