1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Basic file system reading code for standalone I/O system. 31*7c478bd9Sstevel@tonic-gate * Simulates a primitive UNIX I/O system (read(), write(), open(), etc). 32*7c478bd9Sstevel@tonic-gate * Does not support writes. 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate /* 36*7c478bd9Sstevel@tonic-gate * WARNING: 37*7c478bd9Sstevel@tonic-gate * This is currently used by installgrub for creating bootable floppy. 38*7c478bd9Sstevel@tonic-gate * The special part is diskread_callback/fileread_callback for gathering 39*7c478bd9Sstevel@tonic-gate * fileblock list. 40*7c478bd9Sstevel@tonic-gate */ 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/fs/pc_label.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/bootvfs.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/filep.h> 48*7c478bd9Sstevel@tonic-gate #include "pcfilep.h" 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #if defined(_BOOT) 51*7c478bd9Sstevel@tonic-gate #include "../common/util.h" 52*7c478bd9Sstevel@tonic-gate #elif defined(_KERNEL) 53*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 54*7c478bd9Sstevel@tonic-gate #else 55*7c478bd9Sstevel@tonic-gate #include <stdio.h> 56*7c478bd9Sstevel@tonic-gate #include <strings.h> 57*7c478bd9Sstevel@tonic-gate #include <ctype.h> 58*7c478bd9Sstevel@tonic-gate #endif 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #if defined(_BOOT) 61*7c478bd9Sstevel@tonic-gate #define dprintf if (bootrd_debug) printf 62*7c478bd9Sstevel@tonic-gate #elif defined(_KERNEL) 63*7c478bd9Sstevel@tonic-gate #define printf kobj_printf 64*7c478bd9Sstevel@tonic-gate #define dprintf if (bootrd_debug) kobj_printf 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate /* PRINTLIKE */ 67*7c478bd9Sstevel@tonic-gate extern void kobj_printf(char *, ...); 68*7c478bd9Sstevel@tonic-gate #else 69*7c478bd9Sstevel@tonic-gate #define dprintf if (bootrd_debug) printf 70*7c478bd9Sstevel@tonic-gate #endif 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #define FI_STARTCLUST(fp) (*(ushort_t *)(fp)->fi_buf) 73*7c478bd9Sstevel@tonic-gate #define FI_LENGTH(fp) (*(long *)((fp)->fi_buf + 4)) 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate extern int bootrd_debug; 76*7c478bd9Sstevel@tonic-gate extern void *bkmem_alloc(size_t); 77*7c478bd9Sstevel@tonic-gate extern void bkmem_free(void *, size_t); 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * NOTE: The fileread_callback is set by the calling program 81*7c478bd9Sstevel@tonic-gate * during a file read. diskread_callback is set to fileread_callback 82*7c478bd9Sstevel@tonic-gate * only if reading a file block. It needs to be NULL while reading 83*7c478bd9Sstevel@tonic-gate * cluster blocks. 84*7c478bd9Sstevel@tonic-gate */ 85*7c478bd9Sstevel@tonic-gate extern int (*diskread_callback)(int, int); 86*7c478bd9Sstevel@tonic-gate extern int (*fileread_callback)(int, int); 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* 89*7c478bd9Sstevel@tonic-gate * Local prototypes 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate static int lookuppn(char *, _dir_entry_p); 92*7c478bd9Sstevel@tonic-gate static fileid_t *find_fp(int); 93*7c478bd9Sstevel@tonic-gate static void *readblock(int, int); 94*7c478bd9Sstevel@tonic-gate static int fat_map(int, int); 95*7c478bd9Sstevel@tonic-gate static int cluster_valid(long, int); 96*7c478bd9Sstevel@tonic-gate static int fat_ctodb(int, int); 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate static int bpcfs_mountroot(char *str); 99*7c478bd9Sstevel@tonic-gate static int bpcfs_unmountroot(void); 100*7c478bd9Sstevel@tonic-gate static int bpcfs_open(char *str, int flags); 101*7c478bd9Sstevel@tonic-gate static int bpcfs_close(int fd); 102*7c478bd9Sstevel@tonic-gate static void bpcfs_closeall(void); 103*7c478bd9Sstevel@tonic-gate static ssize_t bpcfs_read(int fdesc, char *buf, size_t count); 104*7c478bd9Sstevel@tonic-gate static off_t bpcfs_lseek(int fdesc, off_t addr, int whence); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate static fileid_t *head; 107*7c478bd9Sstevel@tonic-gate static _fat_controller_p pcfsp; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /* cache the cluster */ 110*7c478bd9Sstevel@tonic-gate static int nsec_cache; 111*7c478bd9Sstevel@tonic-gate static int nsec_start; 112*7c478bd9Sstevel@tonic-gate static char *cluster_cache; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 115*7c478bd9Sstevel@tonic-gate static int 116*7c478bd9Sstevel@tonic-gate bpcfs_mountroot(char *str) 117*7c478bd9Sstevel@tonic-gate { 118*7c478bd9Sstevel@tonic-gate int ncluster; 119*7c478bd9Sstevel@tonic-gate if (pcfsp != NULL) 120*7c478bd9Sstevel@tonic-gate return (0); /* already mounted */ 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate pcfsp = bkmem_alloc(sizeof (_fat_controller_t)); 123*7c478bd9Sstevel@tonic-gate head = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 124*7c478bd9Sstevel@tonic-gate head->fi_back = head->fi_forw = head; 125*7c478bd9Sstevel@tonic-gate head->fi_filedes = 0; 126*7c478bd9Sstevel@tonic-gate head->fi_taken = 0; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate /* read of first floppy sector */ 129*7c478bd9Sstevel@tonic-gate head->fi_blocknum = 0; 130*7c478bd9Sstevel@tonic-gate head->fi_count = SECSIZ; 131*7c478bd9Sstevel@tonic-gate head->fi_memp = (caddr_t)pcfsp->f_sector; 132*7c478bd9Sstevel@tonic-gate if (diskread(head)) { 133*7c478bd9Sstevel@tonic-gate printf("failed to read first sector\n"); 134*7c478bd9Sstevel@tonic-gate bkmem_free(pcfsp, sizeof (*pcfsp)); 135*7c478bd9Sstevel@tonic-gate pcfsp = NULL; 136*7c478bd9Sstevel@tonic-gate return (-1); 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate if (pcfsp->f_bpb.bs_spc == 0) { 140*7c478bd9Sstevel@tonic-gate printf("invalid bios paramet block\n"); 141*7c478bd9Sstevel@tonic-gate return (-1); 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate pcfsp->f_rootsec = 145*7c478bd9Sstevel@tonic-gate (pcfsp->f_bpb.bs_num_fats * ltohs(pcfsp->f_bpb.bs_spf)) + 146*7c478bd9Sstevel@tonic-gate ltohs(pcfsp->f_bpb.bs_resv_sectors); 147*7c478bd9Sstevel@tonic-gate pcfsp->f_rootlen = 148*7c478bd9Sstevel@tonic-gate ltohs(pcfsp->f_bpb.bs_num_root_entries) * 149*7c478bd9Sstevel@tonic-gate sizeof (_dir_entry_t) / SECSIZ; 150*7c478bd9Sstevel@tonic-gate pcfsp->f_adjust = 0; 151*7c478bd9Sstevel@tonic-gate pcfsp->f_dclust = CLUSTER_ROOTDIR; 152*7c478bd9Sstevel@tonic-gate pcfsp->f_filesec = pcfsp->f_rootsec + pcfsp->f_rootlen; 153*7c478bd9Sstevel@tonic-gate pcfsp->f_nxtfree = CLUSTER_FIRST; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /* figure out the number of clusters in this partition */ 156*7c478bd9Sstevel@tonic-gate ncluster = (((ulong_t)ltohs(pcfsp->f_bpb.bs_siv) ? 157*7c478bd9Sstevel@tonic-gate (ulong_t)ltohs(pcfsp->f_bpb.bs_siv) : 158*7c478bd9Sstevel@tonic-gate (ulong_t)ltohi(pcfsp->f_bpb.bs_siv)) - 159*7c478bd9Sstevel@tonic-gate pcfsp->f_filesec) / (ulong_t)pcfsp->f_bpb.bs_spc; 160*7c478bd9Sstevel@tonic-gate pcfsp->f_16bit = ncluster >= CLUSTER_MAX_12; 161*7c478bd9Sstevel@tonic-gate pcfsp->f_ncluster = ncluster; 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate /* cache the cluster */ 164*7c478bd9Sstevel@tonic-gate if (pcfsp->f_16bit) 165*7c478bd9Sstevel@tonic-gate nsec_cache = (((ncluster << 1) + 511) >> 9); 166*7c478bd9Sstevel@tonic-gate else 167*7c478bd9Sstevel@tonic-gate nsec_cache = (ncluster + ((ncluster + 1) >> 1) + 511) >> 9; 168*7c478bd9Sstevel@tonic-gate cluster_cache = bkmem_alloc(nsec_cache * SECSIZ); 169*7c478bd9Sstevel@tonic-gate if (cluster_cache == NULL) { 170*7c478bd9Sstevel@tonic-gate printf("bpcfs_mountroot: out of memory\n"); 171*7c478bd9Sstevel@tonic-gate bkmem_free(pcfsp, sizeof (*pcfsp)); 172*7c478bd9Sstevel@tonic-gate pcfsp = NULL; 173*7c478bd9Sstevel@tonic-gate return (-1); 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate head->fi_blocknum = nsec_start = 177*7c478bd9Sstevel@tonic-gate ltohs(pcfsp->f_bpb.bs_resv_sectors) + pcfsp->f_adjust; 178*7c478bd9Sstevel@tonic-gate head->fi_count = nsec_cache * SECSIZ; 179*7c478bd9Sstevel@tonic-gate head->fi_memp = cluster_cache; 180*7c478bd9Sstevel@tonic-gate if (diskread(head)) { 181*7c478bd9Sstevel@tonic-gate printf("bpcfs_mountroot: failed to read cluster\n"); 182*7c478bd9Sstevel@tonic-gate bkmem_free(pcfsp, sizeof (*pcfsp)); 183*7c478bd9Sstevel@tonic-gate pcfsp = NULL; 184*7c478bd9Sstevel@tonic-gate return (-1); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate dprintf("read cluster sectors %d starting at %d\n", 187*7c478bd9Sstevel@tonic-gate nsec_cache, nsec_start); 188*7c478bd9Sstevel@tonic-gate return (0); 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate static int 192*7c478bd9Sstevel@tonic-gate bpcfs_unmountroot(void) 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate if (pcfsp == NULL) 195*7c478bd9Sstevel@tonic-gate return (-1); 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate (void) bpcfs_closeall(); 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate return (0); 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * Open a file. 204*7c478bd9Sstevel@tonic-gate */ 205*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 206*7c478bd9Sstevel@tonic-gate int 207*7c478bd9Sstevel@tonic-gate bpcfs_open(char *str, int flags) 208*7c478bd9Sstevel@tonic-gate { 209*7c478bd9Sstevel@tonic-gate static int filedes = 1; 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate fileid_t *filep; 212*7c478bd9Sstevel@tonic-gate _dir_entry_t d; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate dprintf("open %s\n", str); 215*7c478bd9Sstevel@tonic-gate filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 216*7c478bd9Sstevel@tonic-gate filep->fi_back = head->fi_back; 217*7c478bd9Sstevel@tonic-gate filep->fi_forw = head; 218*7c478bd9Sstevel@tonic-gate head->fi_back->fi_forw = filep; 219*7c478bd9Sstevel@tonic-gate head->fi_back = filep; 220*7c478bd9Sstevel@tonic-gate filep->fi_filedes = filedes++; 221*7c478bd9Sstevel@tonic-gate filep->fi_taken = 1; 222*7c478bd9Sstevel@tonic-gate filep->fi_path = (char *)bkmem_alloc(strlen(str) + 1); 223*7c478bd9Sstevel@tonic-gate (void) strcpy(filep->fi_path, str); 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate if (lookuppn(str, &d)) { 226*7c478bd9Sstevel@tonic-gate (void) bpcfs_close(filep->fi_filedes); 227*7c478bd9Sstevel@tonic-gate return (-1); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate filep->fi_offset = 0; 231*7c478bd9Sstevel@tonic-gate FI_STARTCLUST(filep) = d.d_cluster; 232*7c478bd9Sstevel@tonic-gate FI_LENGTH(filep) = d.d_size; 233*7c478bd9Sstevel@tonic-gate dprintf("file %s size = %ld\n", str, d.d_size); 234*7c478bd9Sstevel@tonic-gate return (filep->fi_filedes); 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate int 238*7c478bd9Sstevel@tonic-gate bpcfs_close(int fd) 239*7c478bd9Sstevel@tonic-gate { 240*7c478bd9Sstevel@tonic-gate fileid_t *filep; 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate dprintf("close %d\n", fd); 243*7c478bd9Sstevel@tonic-gate if (!(filep = find_fp(fd))) 244*7c478bd9Sstevel@tonic-gate return (-1); 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate if (filep->fi_taken == 0 || filep == head) { 247*7c478bd9Sstevel@tonic-gate printf("File descripter %d no allocated!\n", fd); 248*7c478bd9Sstevel@tonic-gate return (-1); 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate /* unlink and deallocate node */ 252*7c478bd9Sstevel@tonic-gate filep->fi_forw->fi_back = filep->fi_back; 253*7c478bd9Sstevel@tonic-gate filep->fi_back->fi_forw = filep->fi_forw; 254*7c478bd9Sstevel@tonic-gate bkmem_free(filep->fi_path, strlen(filep->fi_path) + 1); 255*7c478bd9Sstevel@tonic-gate bkmem_free((char *)filep, sizeof (fileid_t)); 256*7c478bd9Sstevel@tonic-gate dprintf("close done\n"); 257*7c478bd9Sstevel@tonic-gate return (0); 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate static void 261*7c478bd9Sstevel@tonic-gate bpcfs_closeall(void) 262*7c478bd9Sstevel@tonic-gate { 263*7c478bd9Sstevel@tonic-gate fileid_t *filep; 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate while ((filep = head->fi_forw) != head) 266*7c478bd9Sstevel@tonic-gate if (filep->fi_taken && bpcfs_close(filep->fi_filedes)) 267*7c478bd9Sstevel@tonic-gate printf("Filesystem may be inconsistent.\n"); 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate bkmem_free(pcfsp, sizeof (*pcfsp)); 270*7c478bd9Sstevel@tonic-gate bkmem_free(head, sizeof (fileid_t)); 271*7c478bd9Sstevel@tonic-gate pcfsp = NULL; 272*7c478bd9Sstevel@tonic-gate head = NULL; 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate static ssize_t 276*7c478bd9Sstevel@tonic-gate bpcfs_read(int fd, caddr_t b, size_t c) 277*7c478bd9Sstevel@tonic-gate { 278*7c478bd9Sstevel@tonic-gate ulong_t sector; 279*7c478bd9Sstevel@tonic-gate uint_t count = 0, xfer, i; 280*7c478bd9Sstevel@tonic-gate char *block; 281*7c478bd9Sstevel@tonic-gate ulong_t off, blk; 282*7c478bd9Sstevel@tonic-gate int rd, spc; 283*7c478bd9Sstevel@tonic-gate fileid_t *fp; 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate dprintf("bpcfs_read: fd = %d, buf = %p, size = %d\n", 286*7c478bd9Sstevel@tonic-gate fd, (void *)b, c); 287*7c478bd9Sstevel@tonic-gate fp = find_fp(fd); 288*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 289*7c478bd9Sstevel@tonic-gate printf("invalid file descriptor %d\n", fd); 290*7c478bd9Sstevel@tonic-gate return (-1); 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate spc = pcfsp->f_bpb.bs_spc; 294*7c478bd9Sstevel@tonic-gate off = fp->fi_offset; 295*7c478bd9Sstevel@tonic-gate blk = FI_STARTCLUST(fp); 296*7c478bd9Sstevel@tonic-gate rd = blk == CLUSTER_ROOTDIR ? 1 : 0; 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate spc = pcfsp->f_bpb.bs_spc; 299*7c478bd9Sstevel@tonic-gate off = fp->fi_offset; 300*7c478bd9Sstevel@tonic-gate blk = FI_STARTCLUST(fp); 301*7c478bd9Sstevel@tonic-gate rd = (blk == CLUSTER_ROOTDIR) ? 1 : 0; 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate if ((c = MIN(FI_LENGTH(fp) - off, c)) == 0) 304*7c478bd9Sstevel@tonic-gate return (0); 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate while (off >= pcfsp->f_bpb.bs_spc * SECSIZ) { 307*7c478bd9Sstevel@tonic-gate blk = fat_map(blk, rd); 308*7c478bd9Sstevel@tonic-gate off -= pcfsp->f_bpb.bs_spc * SECSIZ; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate if (!cluster_valid(blk, rd)) { 311*7c478bd9Sstevel@tonic-gate printf("bpcfs_read: invalid cluster: %ld, %d\n", 312*7c478bd9Sstevel@tonic-gate blk, rd); 313*7c478bd9Sstevel@tonic-gate return (-1); 314*7c478bd9Sstevel@tonic-gate } 315*7c478bd9Sstevel@tonic-gate } 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate while (count < c) { 318*7c478bd9Sstevel@tonic-gate sector = fat_ctodb(blk, rd); 319*7c478bd9Sstevel@tonic-gate diskread_callback = fileread_callback; 320*7c478bd9Sstevel@tonic-gate for (i = ((off / SECSIZ) % pcfsp->f_bpb.bs_spc); i < spc; i++) { 321*7c478bd9Sstevel@tonic-gate xfer = MIN(SECSIZ - (off % SECSIZ), c - count); 322*7c478bd9Sstevel@tonic-gate if (xfer == 0) 323*7c478bd9Sstevel@tonic-gate break; /* last sector done */ 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate block = (char *)readblock(sector + i, 1); 326*7c478bd9Sstevel@tonic-gate if (block == NULL) { 327*7c478bd9Sstevel@tonic-gate return (-1); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate dprintf("bpcfs_read: read %d bytes\n", xfer); 330*7c478bd9Sstevel@tonic-gate if (diskread_callback == NULL) 331*7c478bd9Sstevel@tonic-gate (void) bcopy(&block[off % SECSIZ], b, xfer); 332*7c478bd9Sstevel@tonic-gate count += xfer; 333*7c478bd9Sstevel@tonic-gate off += xfer; 334*7c478bd9Sstevel@tonic-gate b += xfer; 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate diskread_callback = NULL; 338*7c478bd9Sstevel@tonic-gate if (count < c) { 339*7c478bd9Sstevel@tonic-gate blk = fat_map(blk, rd); 340*7c478bd9Sstevel@tonic-gate if (!cluster_valid(blk, rd)) { 341*7c478bd9Sstevel@tonic-gate printf("bpcfs_read: invalid cluster: %ld, %d\n", 342*7c478bd9Sstevel@tonic-gate blk, rd); 343*7c478bd9Sstevel@tonic-gate break; 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate fp->fi_offset += count; 349*7c478bd9Sstevel@tonic-gate return (count); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate /* 353*7c478bd9Sstevel@tonic-gate * This version of seek() only performs absolute seeks (whence == 0). 354*7c478bd9Sstevel@tonic-gate */ 355*7c478bd9Sstevel@tonic-gate static off_t 356*7c478bd9Sstevel@tonic-gate bpcfs_lseek(int fd, off_t addr, int whence) 357*7c478bd9Sstevel@tonic-gate { 358*7c478bd9Sstevel@tonic-gate fileid_t *filep; 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate dprintf("lseek %d, off = %lx\n", fd, addr); 361*7c478bd9Sstevel@tonic-gate if (!(filep = find_fp(fd))) 362*7c478bd9Sstevel@tonic-gate return (-1); 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate switch (whence) { 365*7c478bd9Sstevel@tonic-gate case SEEK_CUR: 366*7c478bd9Sstevel@tonic-gate filep->fi_offset += addr; 367*7c478bd9Sstevel@tonic-gate break; 368*7c478bd9Sstevel@tonic-gate case SEEK_SET: 369*7c478bd9Sstevel@tonic-gate filep->fi_offset = addr; 370*7c478bd9Sstevel@tonic-gate break; 371*7c478bd9Sstevel@tonic-gate default: 372*7c478bd9Sstevel@tonic-gate case SEEK_END: 373*7c478bd9Sstevel@tonic-gate printf("lseek(): invalid whence value %d\n", whence); 374*7c478bd9Sstevel@tonic-gate break; 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate filep->fi_blocknum = addr / DEV_BSIZE; 378*7c478bd9Sstevel@tonic-gate filep->fi_count = 0; 379*7c478bd9Sstevel@tonic-gate return (0); 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate static fileid_t * 383*7c478bd9Sstevel@tonic-gate find_fp(int fd) 384*7c478bd9Sstevel@tonic-gate { 385*7c478bd9Sstevel@tonic-gate fileid_t *filep = head; 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate if (fd >= 0) { 388*7c478bd9Sstevel@tonic-gate while ((filep = filep->fi_forw) != head) 389*7c478bd9Sstevel@tonic-gate if (fd == filep->fi_filedes) 390*7c478bd9Sstevel@tonic-gate return (filep->fi_taken ? filep : 0); 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate return (0); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate static int 397*7c478bd9Sstevel@tonic-gate cluster_valid(long c, int rd) 398*7c478bd9Sstevel@tonic-gate { 399*7c478bd9Sstevel@tonic-gate return ((rd && (c == 0)) ? 1 : (c >= CLUSTER_RES_16_0 ? 0 : c)); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate static int 403*7c478bd9Sstevel@tonic-gate fat_ctodb(int blk, int r) 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate uint_t s; 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate s = r ? blk + pcfsp->f_rootsec + pcfsp->f_adjust : 408*7c478bd9Sstevel@tonic-gate ((blk - 2) * pcfsp->f_bpb.bs_spc) + 409*7c478bd9Sstevel@tonic-gate pcfsp->f_filesec + pcfsp->f_adjust; 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate return (s); 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate static int 415*7c478bd9Sstevel@tonic-gate fat_map(int blk, int rootdir) 416*7c478bd9Sstevel@tonic-gate { 417*7c478bd9Sstevel@tonic-gate ulong_t sectn, fat_index; 418*7c478bd9Sstevel@tonic-gate uchar_t *fp; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate if (rootdir) { 421*7c478bd9Sstevel@tonic-gate return (blk > pcfsp->f_rootlen ? CLUSTER_EOF : blk + 1); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate /* ---- Find out what sector this cluster is in ---- */ 425*7c478bd9Sstevel@tonic-gate fat_index = (pcfsp->f_16bit) ? ((ulong_t)blk << 1) : 426*7c478bd9Sstevel@tonic-gate ((ulong_t)blk + ((uint_t)blk >> 1)); 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate sectn = (fat_index / SECSIZ) + ltohs(pcfsp->f_bpb.bs_resv_sectors) 429*7c478bd9Sstevel@tonic-gate + pcfsp->f_adjust; 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate /* 432*7c478bd9Sstevel@tonic-gate * Read two sectors so that if our fat_index points at the last byte 433*7c478bd9Sstevel@tonic-gate * byte we'll have the data needed. This is only a problem for fat12 434*7c478bd9Sstevel@tonic-gate * entries. 435*7c478bd9Sstevel@tonic-gate */ 436*7c478bd9Sstevel@tonic-gate if (!(fp = (uchar_t *)readblock(sectn, 2))) { 437*7c478bd9Sstevel@tonic-gate printf("fat_map: bad cluster\n"); 438*7c478bd9Sstevel@tonic-gate return (CLUSTER_BAD_16); 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate fp += (fat_index % SECSIZ); 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate if (pcfsp->f_16bit) 444*7c478bd9Sstevel@tonic-gate blk = fp[0] | (fp[1] << 8); 445*7c478bd9Sstevel@tonic-gate else { 446*7c478bd9Sstevel@tonic-gate if (blk & 1) 447*7c478bd9Sstevel@tonic-gate blk = ((fp[0] >> 4) & 0xf) | (fp[1] << 4); 448*7c478bd9Sstevel@tonic-gate else 449*7c478bd9Sstevel@tonic-gate blk = ((fp[1] & 0xf) << 8) | fp[0]; 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate /* 452*7c478bd9Sstevel@tonic-gate * This makes compares easier because we can just compare 453*7c478bd9Sstevel@tonic-gate * against one value instead of two. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate if (blk >= CLUSTER_RES_12_0) 456*7c478bd9Sstevel@tonic-gate blk |= CLUSTER_RES_16_0; 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate return (blk); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate static int 462*7c478bd9Sstevel@tonic-gate namecmp(char *pn, char *dn, int cs) 463*7c478bd9Sstevel@tonic-gate { 464*7c478bd9Sstevel@tonic-gate dprintf("namecmp %s, %s, len = %d\n", pn, dn, cs); 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate /* starting char must match */ 467*7c478bd9Sstevel@tonic-gate while (*pn && *dn) { 468*7c478bd9Sstevel@tonic-gate --cs; 469*7c478bd9Sstevel@tonic-gate if (toupper(*pn++) != toupper(*dn++)) 470*7c478bd9Sstevel@tonic-gate return (1); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate dprintf("namecmp: cs = %d\n", cs); 474*7c478bd9Sstevel@tonic-gate /* remainder should be either ~# or all spaces */ 475*7c478bd9Sstevel@tonic-gate if (cs > 0 && *dn == '~') 476*7c478bd9Sstevel@tonic-gate return (0); 477*7c478bd9Sstevel@tonic-gate while (cs > 0) { 478*7c478bd9Sstevel@tonic-gate if (*dn++ != ' ') 479*7c478bd9Sstevel@tonic-gate return (1); 480*7c478bd9Sstevel@tonic-gate --cs; 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate return (0); 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate static int 486*7c478bd9Sstevel@tonic-gate dircmp(char *name, char *d_name, char *d_ext) 487*7c478bd9Sstevel@tonic-gate { 488*7c478bd9Sstevel@tonic-gate int ret; 489*7c478bd9Sstevel@tonic-gate char *sep, *ext; 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate sep = (char *)strchr(name, '.'); 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate if (sep) { 494*7c478bd9Sstevel@tonic-gate *sep = '\0'; 495*7c478bd9Sstevel@tonic-gate ext = sep + 1; 496*7c478bd9Sstevel@tonic-gate } else 497*7c478bd9Sstevel@tonic-gate ext = " "; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate if (namecmp(name, d_name, NAMESIZ) || namecmp(ext, d_ext, EXTSIZ)) 500*7c478bd9Sstevel@tonic-gate ret = 1; 501*7c478bd9Sstevel@tonic-gate else 502*7c478bd9Sstevel@tonic-gate ret = 0; 503*7c478bd9Sstevel@tonic-gate if (sep) 504*7c478bd9Sstevel@tonic-gate *sep = '.'; 505*7c478bd9Sstevel@tonic-gate return (ret); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate static int 509*7c478bd9Sstevel@tonic-gate lookup(char *n, _dir_entry_p dp, ulong_t dir_blk) 510*7c478bd9Sstevel@tonic-gate { 511*7c478bd9Sstevel@tonic-gate int spc = pcfsp->f_bpb.bs_spc; 512*7c478bd9Sstevel@tonic-gate int rd = (dir_blk == CLUSTER_ROOTDIR ? 1 : 0); 513*7c478bd9Sstevel@tonic-gate _dir_entry_p dxp; 514*7c478bd9Sstevel@tonic-gate int j, sector; 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate dprintf("lookup: name = %s\n", n); 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate while (cluster_valid(dir_blk, rd)) { 519*7c478bd9Sstevel@tonic-gate sector = fat_ctodb(dir_blk, rd); 520*7c478bd9Sstevel@tonic-gate dxp = readblock(sector, 1); /* read one sector */ 521*7c478bd9Sstevel@tonic-gate if (dxp == NULL) 522*7c478bd9Sstevel@tonic-gate return (0); 523*7c478bd9Sstevel@tonic-gate for (j = 0; j < DIRENTS * spc; j++, dxp++) { 524*7c478bd9Sstevel@tonic-gate dprintf("lookup: dir entry %s.%s;\n", 525*7c478bd9Sstevel@tonic-gate dxp->d_name, dxp->d_ext); 526*7c478bd9Sstevel@tonic-gate if (dxp->d_name[0] == 0) 527*7c478bd9Sstevel@tonic-gate return (0); 528*7c478bd9Sstevel@tonic-gate if ((uchar_t)dxp->d_name[0] != 0xE5 && 529*7c478bd9Sstevel@tonic-gate (dxp->d_attr & (DE_LABEL|DE_HIDDEN)) == 0 && 530*7c478bd9Sstevel@tonic-gate dircmp(n, dxp->d_name, dxp->d_ext) == 0) { 531*7c478bd9Sstevel@tonic-gate dprintf("lookup: match found\n"); 532*7c478bd9Sstevel@tonic-gate (void) bcopy(dxp, dp, sizeof (*dp)); 533*7c478bd9Sstevel@tonic-gate return (1); 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate /* next cluster */ 537*7c478bd9Sstevel@tonic-gate dir_blk = fat_map(dir_blk, rd); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate return (0); 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate static int 544*7c478bd9Sstevel@tonic-gate lookuppn(char *n, _dir_entry_p dp) 545*7c478bd9Sstevel@tonic-gate { 546*7c478bd9Sstevel@tonic-gate long dir_blk; 547*7c478bd9Sstevel@tonic-gate char name[8 + 1 + 3 + 1]; /* <8>.<3>'\0' */ 548*7c478bd9Sstevel@tonic-gate char *p, *ep; 549*7c478bd9Sstevel@tonic-gate _dir_entry_t dd; 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate dprintf("lookuppn: path = %s\n", n); 552*7c478bd9Sstevel@tonic-gate dir_blk = pcfsp->f_dclust; 553*7c478bd9Sstevel@tonic-gate if ((*n == '\\') || (*n == '/')) { 554*7c478bd9Sstevel@tonic-gate dir_blk = CLUSTER_ROOTDIR; 555*7c478bd9Sstevel@tonic-gate while ((*n == '\\') || (*n == '/')) 556*7c478bd9Sstevel@tonic-gate n++; 557*7c478bd9Sstevel@tonic-gate if (*n == '\0') { 558*7c478bd9Sstevel@tonic-gate (void) bzero(dp, sizeof (*dp)); 559*7c478bd9Sstevel@tonic-gate dp->d_cluster = CLUSTER_ROOTDIR; 560*7c478bd9Sstevel@tonic-gate dp->d_attr = DE_DIRECTORY; 561*7c478bd9Sstevel@tonic-gate return (0); 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate ep = &name[0] + sizeof (name); 566*7c478bd9Sstevel@tonic-gate while (*n) { 567*7c478bd9Sstevel@tonic-gate (void) bzero(name, sizeof (name)); 568*7c478bd9Sstevel@tonic-gate p = &name[0]; 569*7c478bd9Sstevel@tonic-gate while (*n && (*n != '\\') && (*n != '/')) 570*7c478bd9Sstevel@tonic-gate if (p != ep) 571*7c478bd9Sstevel@tonic-gate *p++ = *n++; 572*7c478bd9Sstevel@tonic-gate else { 573*7c478bd9Sstevel@tonic-gate dprintf("return, name %s is too long\n", name); 574*7c478bd9Sstevel@tonic-gate return (-1); /* name is too long */ 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate while ((*n == '\\') || (*n == '/')) 577*7c478bd9Sstevel@tonic-gate n++; 578*7c478bd9Sstevel@tonic-gate if (lookup(name, &dd, dir_blk) == 0) { 579*7c478bd9Sstevel@tonic-gate dprintf("return, name %s not found\n", name); 580*7c478bd9Sstevel@tonic-gate return (-1); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate dprintf("dd = %x:%x:%x attr = %x\n", 583*7c478bd9Sstevel@tonic-gate *(int *)&dd, *(((int *)&dd) + 1), 584*7c478bd9Sstevel@tonic-gate *(((int *)&dd) + 2), dd.d_attr); 585*7c478bd9Sstevel@tonic-gate if (*n && ((dd.d_attr & DE_DIRECTORY) == 0)) { 586*7c478bd9Sstevel@tonic-gate dprintf("return, not a directory\n"); 587*7c478bd9Sstevel@tonic-gate return (-1); 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate dir_blk = dd.d_cluster; 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate (void) bcopy(&dd, dp, sizeof (dd)); 593*7c478bd9Sstevel@tonic-gate return (0); 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate static void * 597*7c478bd9Sstevel@tonic-gate readblock(int sector, int nsec) 598*7c478bd9Sstevel@tonic-gate { 599*7c478bd9Sstevel@tonic-gate if (sector >= nsec_start && sector + nsec <= nsec_start + nsec_cache) 600*7c478bd9Sstevel@tonic-gate return (cluster_cache + (sector - nsec_start) * SECSIZ); 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate /* read disk sectors */ 603*7c478bd9Sstevel@tonic-gate head->fi_blocknum = sector; 604*7c478bd9Sstevel@tonic-gate head->fi_count = nsec * SECSIZ; 605*7c478bd9Sstevel@tonic-gate head->fi_memp = head->fi_buf; 606*7c478bd9Sstevel@tonic-gate if (diskread(head)) { 607*7c478bd9Sstevel@tonic-gate printf("failed to %d sectors at %d\n", nsec, sector); 608*7c478bd9Sstevel@tonic-gate return (NULL); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate return (head->fi_buf); 612*7c478bd9Sstevel@tonic-gate } 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate struct boot_fs_ops bpcfs_ops = { 615*7c478bd9Sstevel@tonic-gate "boot_pcfs", 616*7c478bd9Sstevel@tonic-gate bpcfs_mountroot, 617*7c478bd9Sstevel@tonic-gate bpcfs_unmountroot, 618*7c478bd9Sstevel@tonic-gate bpcfs_open, 619*7c478bd9Sstevel@tonic-gate bpcfs_close, 620*7c478bd9Sstevel@tonic-gate bpcfs_read, 621*7c478bd9Sstevel@tonic-gate bpcfs_lseek, 622*7c478bd9Sstevel@tonic-gate NULL 623*7c478bd9Sstevel@tonic-gate }; 624