1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2013 Joyent, Inc. All rights reserved. 14 */ 15 16 #include <sys/bootconf.h> 17 #include <sys/types.h> 18 #include <sys/param.h> 19 #include <sys/vnode.h> 20 #include <sys/fs/ufs_fsdir.h> 21 #include <sys/fs/ufs_fs.h> 22 #include <sys/fs/ufs_inode.h> 23 #include <sys/sysmacros.h> 24 #include <sys/bootvfs.h> 25 #include <sys/bootinfo.h> 26 #include <sys/filep.h> 27 28 #ifdef _BOOT 29 #include "../common/util.h" 30 #else 31 #include <sys/sunddi.h> 32 #endif 33 34 #define MAX_FILES MAX_BOOT_MODULES 35 #define MAX_FDS 256 36 37 extern void *bkmem_alloc(size_t); 38 extern void bkmem_free(void *, size_t); 39 40 /* 41 * TODO: Replace these declarations with inclusion of the ordinary userland 42 * bootfs headers once they're available. 43 */ 44 typedef struct bfile { 45 char bf_name[MAXPATHLEN]; 46 caddr_t bf_addr; 47 size_t bf_size; 48 struct bfile *bf_next; 49 uint64_t bf_ino; 50 } bfile_t; 51 52 typedef struct bf_fd { 53 bfile_t *fd_file; 54 off_t fd_pos; 55 } bf_fd_t; 56 57 static bfile_t *head; 58 static uint_t init_done; 59 static bf_fd_t fds[MAX_FDS]; 60 61 static char cpath[MAXPATHLEN]; /* For canonicalising filenames */ 62 63 static void bbootfs_closeall(int); 64 65 static void 66 canonicalise(const char *fn, char *out) 67 { 68 const char *p; 69 char *q, *s; 70 char *last; 71 char *oc; 72 int is_slash = 0; 73 static char scratch[MAXPATHLEN]; 74 75 if (fn == NULL) { 76 *out = '\0'; 77 return; 78 } 79 80 /* 81 * Remove leading slashes and condense all multiple slashes into one. 82 */ 83 p = fn; 84 while (*p == '/') 85 ++p; 86 87 for (q = scratch; *p != '\0'; p++) { 88 if (*p == '/' && !is_slash) { 89 *q++ = '/'; 90 is_slash = 1; 91 } else if (*p != '/') { 92 *q++ = *p; 93 is_slash = 0; 94 } 95 } 96 *q = '\0'; 97 98 if (strncmp(scratch, "system/boot/", 12) == 0 || 99 strcmp(scratch, "system/boot") == 0) { 100 s = scratch + 12; 101 } else { 102 s = scratch; 103 } 104 105 for (last = strsep(&s, "/"), q = oc = out; last != NULL; 106 last = strsep(&s, "/")) { 107 if (strcmp(last, ".") == 0) 108 continue; 109 if (strcmp(last, "..") == 0) { 110 for (oc = q; oc > out && *oc != '/'; oc--) 111 ; 112 q = oc; 113 continue; 114 } 115 if (q > out) 116 *q++ = '/'; 117 q += snprintf(q, MAXPATHLEN - (q - out), "%s", last); 118 } 119 120 *q = '\0'; 121 } 122 123 /* ARGSUSED */ 124 static int 125 bbootfs_mountroot(char *str) 126 { 127 return (-1); 128 } 129 130 static int 131 bbootfs_unmountroot(void) 132 { 133 return (-1); 134 } 135 136 static int 137 bbootfs_init(void) 138 { 139 bfile_t *fp; 140 char propname[32]; 141 uint64_t propval; 142 uint_t i; 143 144 for (i = 0; i < MAX_FILES; i++) { 145 (void) snprintf(propname, sizeof (propname), 146 "module-name-%u", i); 147 if (do_bsys_getproplen(NULL, propname) < 0) 148 break; 149 150 if ((fp = bkmem_alloc(sizeof (bfile_t))) == NULL) { 151 bbootfs_closeall(1); 152 return (-1); 153 } 154 155 (void) do_bsys_getprop(NULL, propname, cpath); 156 canonicalise(cpath, fp->bf_name); 157 158 (void) snprintf(propname, sizeof (propname), 159 "module-addr-%u", i); 160 if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) { 161 bkmem_free(fp, sizeof (bfile_t)); 162 continue; 163 } 164 (void) do_bsys_getprop(NULL, propname, &propval); 165 fp->bf_addr = (void *)(uintptr_t)propval; 166 167 (void) snprintf(propname, sizeof (propname), 168 "module-size-%u", i); 169 if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) { 170 bkmem_free(fp, sizeof (bfile_t)); 171 continue; 172 } 173 (void) do_bsys_getprop(NULL, propname, &propval); 174 fp->bf_size = (size_t)propval; 175 fp->bf_ino = i; 176 177 fp->bf_next = head; 178 head = fp; 179 } 180 181 return (0); 182 } 183 184 /*ARGSUSED*/ 185 static int 186 bbootfs_open(char *fn, int flags) 187 { 188 uint_t i; 189 bfile_t *fp; 190 191 if (!init_done) { 192 if (bbootfs_init() != 0) 193 return (-1); 194 195 init_done = 1; 196 } 197 198 canonicalise(fn, cpath); 199 200 for (fp = head; fp != NULL; fp = fp->bf_next) { 201 if (strcmp(fp->bf_name, cpath) == 0) 202 break; 203 } 204 205 if (fp == NULL) 206 return (-1); 207 208 for (i = 0; i < MAX_FDS; i++) { 209 if (fds[i].fd_file == NULL) { 210 fds[i].fd_file = fp; 211 fds[i].fd_pos = 0; 212 return (i); 213 } 214 } 215 216 return (-1); 217 } 218 219 static int 220 bbootfs_close(int fd) 221 { 222 if (fds[fd].fd_file == NULL) 223 return (-1); 224 225 fds[fd].fd_file = NULL; 226 fds[fd].fd_pos = 0; 227 228 return (0); 229 } 230 231 static ssize_t 232 bbootfs_read(int fd, caddr_t buf, size_t size) 233 { 234 ssize_t len; 235 bf_fd_t *fdp = &fds[fd]; 236 237 if (fdp->fd_file == NULL) 238 return (-1); 239 240 if (fdp->fd_pos >= fdp->fd_file->bf_size) 241 return (-1); 242 243 if (fdp->fd_pos + size > fdp->fd_file->bf_size) 244 len = fdp->fd_file->bf_size - fdp->fd_pos; 245 else 246 len = size; 247 248 bcopy(fdp->fd_file->bf_addr + fdp->fd_pos, buf, len); 249 250 fdp->fd_pos += len; 251 252 return (len); 253 } 254 255 static off_t 256 bbootfs_lseek(int fd, off_t addr, int whence) 257 { 258 bf_fd_t *fdp = &fds[fd]; 259 260 if (fdp->fd_file == NULL) 261 return (-1); 262 263 switch (whence) { 264 case SEEK_CUR: 265 fdp->fd_pos += addr; 266 break; 267 case SEEK_SET: 268 fdp->fd_pos = addr; 269 break; 270 case SEEK_END: 271 fdp->fd_pos = fdp->fd_file->bf_size; 272 break; 273 default: 274 return (-1); 275 } 276 277 return (0); 278 } 279 280 static int 281 bbootfs_fstat(int fd, struct bootstat *bsp) 282 { 283 bf_fd_t *fdp = &fds[fd]; 284 285 if (fdp->fd_file == NULL) 286 return (-1); 287 288 bsp->st_dev = 1; 289 bsp->st_ino = fdp->fd_file->bf_ino; 290 bsp->st_mode = 0444; 291 bsp->st_nlink = 1; 292 bsp->st_uid = bsp->st_gid = 0; 293 bsp->st_rdev = 0; 294 bsp->st_size = fdp->fd_file->bf_size; 295 bsp->st_blksize = 1; 296 bsp->st_blocks = fdp->fd_file->bf_size; 297 (void) strcpy(bsp->st_fstype, "bootfs"); 298 299 return (0); 300 } 301 302 /* ARGSUSED */ 303 static void 304 bbootfs_closeall(int flag) 305 { 306 bfile_t *fp; 307 308 while (head != NULL) { 309 fp = head; 310 head = head->bf_next; 311 312 bkmem_free(fp, sizeof (bfile_t)); 313 } 314 315 init_done = 0; 316 } 317 318 struct boot_fs_ops bbootfs_ops = { 319 "bootfs", 320 bbootfs_mountroot, 321 bbootfs_unmountroot, 322 bbootfs_open, 323 bbootfs_close, 324 bbootfs_read, 325 bbootfs_lseek, 326 bbootfs_fstat, 327 bbootfs_closeall, 328 NULL 329 }; 330