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 * Copyright 2013 Joyent, Inc. All rights reserved. 25 */ 26 27 28 #include <sys/param.h> 29 #include <sys/sunddi.h> 30 #include <sys/bootconf.h> 31 #include <sys/bootvfs.h> 32 #include <sys/filep.h> 33 #include <sys/kobj.h> 34 #include <sys/varargs.h> 35 #include <sys/reboot.h> 36 37 extern void (*_kobj_printf)(void *, const char *fmt, ...); 38 extern int get_weakish_int(int *); 39 extern struct bootops *ops; 40 extern struct boot_fs_ops bufs_ops, bhsfs_ops, bbootfs_ops; 41 extern int kmem_ready; 42 43 static uint64_t rd_start, rd_end; 44 struct boot_fs_ops *bfs_ops; 45 struct boot_fs_ops *bfs_tab[] = {&bufs_ops, &bhsfs_ops, &bbootfs_ops, NULL}; 46 47 static uintptr_t scratch_max = 0; 48 49 #define _kmem_ready get_weakish_int(&kmem_ready) 50 51 int 52 BRD_MOUNTROOT(struct boot_fs_ops *ops, char *str) 53 { 54 return (ops->fsw_mountroot(str)); 55 } 56 57 int 58 BRD_UNMOUNTROOT(struct boot_fs_ops *ops) 59 { 60 if (bfs_ops != &bbootfs_ops) 61 bbootfs_ops.fsw_closeall(1); 62 63 return (ops->fsw_unmountroot()); 64 } 65 66 int 67 BRD_OPEN(struct boot_fs_ops *ops, char *file, int flags) 68 { 69 int len = strlen(SYSTEM_BOOT_PATH); 70 int fd; 71 72 /* 73 * Our policy is that we try bootfs first. If bootfs is the only 74 * filesystem, that's the end of it. Otherwise we will fall back to 75 * the normal root (i.e., ramdisk) filesystem at this point and try 76 * again if the file does not exist in bootfs. 77 */ 78 fd = bbootfs_ops.fsw_open(file, flags); 79 80 if (bfs_ops == &bbootfs_ops) 81 return (fd); 82 83 if (strncmp(file, SYSTEM_BOOT_PATH, len) == 0 || fd >= 0) 84 return ((fd < 0) ? fd : (fd | BFD_F_SYSTEM_BOOT)); 85 86 return (ops->fsw_open(file, flags)); 87 } 88 89 int 90 BRD_CLOSE(struct boot_fs_ops *ops, int fd) 91 { 92 if (fd & BFD_F_SYSTEM_BOOT) 93 return (bbootfs_ops.fsw_close(fd & ~BFD_F_SYSTEM_BOOT)); 94 95 return (ops->fsw_close(fd)); 96 } 97 98 ssize_t 99 BRD_READ(struct boot_fs_ops *ops, int fd, caddr_t buf, size_t len) 100 { 101 if (fd & BFD_F_SYSTEM_BOOT) { 102 return (bbootfs_ops.fsw_read(fd & ~BFD_F_SYSTEM_BOOT, 103 buf, len)); 104 } 105 106 return (ops->fsw_read(fd, buf, len)); 107 } 108 109 off_t 110 BRD_SEEK(struct boot_fs_ops *ops, int fd, off_t addr, int whence) 111 { 112 if (fd & BFD_F_SYSTEM_BOOT) { 113 return (bbootfs_ops.fsw_lseek(fd & ~BFD_F_SYSTEM_BOOT, 114 addr, whence)); 115 } 116 117 return (ops->fsw_lseek(fd, addr, whence)); 118 } 119 120 int 121 BRD_FSTAT(struct boot_fs_ops *ops, int fd, struct bootstat *bsp) 122 { 123 if (fd & BFD_F_SYSTEM_BOOT) 124 return (bbootfs_ops.fsw_fstat(fd & ~BFD_F_SYSTEM_BOOT, bsp)); 125 126 return (ops->fsw_fstat(fd, bsp)); 127 } 128 129 /* 130 * This one reads the ramdisk. If fi_memp is set, we copy the 131 * ramdisk content to the designated buffer. Otherwise, we 132 * do a "cached" read (set fi_memp to the actual ramdisk buffer). 133 */ 134 int 135 diskread(fileid_t *filep) 136 { 137 uint_t blocknum; 138 caddr_t diskloc; 139 140 /* add in offset of root slice */ 141 blocknum = filep->fi_blocknum; 142 143 diskloc = (caddr_t)(uintptr_t)rd_start + blocknum * DEV_BSIZE; 144 if (diskloc + filep->fi_count > (caddr_t)(uintptr_t)rd_end) { 145 _kobj_printf(ops, "diskread: start = 0x%p, size = 0x%x\n", 146 diskloc, filep->fi_count); 147 _kobj_printf(ops, "reading beyond end of ramdisk\n"); 148 return (-1); 149 } 150 151 if (filep->fi_memp) { 152 bcopy(diskloc, filep->fi_memp, filep->fi_count); 153 } else { 154 /* "cached" read */ 155 filep->fi_memp = diskloc; 156 } 157 158 return (0); 159 } 160 161 int 162 kobj_boot_mountroot() 163 { 164 int i; 165 166 if (BOP_GETPROPLEN(ops, "ramdisk_start") != 8 || 167 BOP_GETPROP(ops, "ramdisk_start", (void *)&rd_start) != 0 || 168 BOP_GETPROPLEN(ops, "ramdisk_end") != 8 || 169 BOP_GETPROP(ops, "ramdisk_end", (void *)&rd_end) != 0) { 170 _kobj_printf(ops, 171 "failed to get ramdisk from boot\n"); 172 return (-1); 173 } 174 #ifdef KOBJ_DEBUG 175 _kobj_printf(ops, 176 "ramdisk range: 0x%llx-%llx\n", rd_start, rd_end); 177 #endif 178 179 for (i = 0; bfs_tab[i] != NULL; i++) { 180 bfs_ops = bfs_tab[i]; 181 if (BRD_MOUNTROOT(bfs_ops, "dummy") == 0) 182 return (0); 183 } 184 _kobj_printf(ops, "failed to mount ramdisk from boot\n"); 185 return (-1); 186 } 187 188 void 189 kobj_boot_unmountroot() 190 { 191 #ifdef DEBUG 192 if (boothowto & RB_VERBOSE) 193 _kobj_printf(ops, "boot scratch memory used: 0x%lx\n", 194 scratch_max); 195 #endif 196 (void) BRD_UNMOUNTROOT(bfs_ops); 197 } 198 199 /* 200 * Boot time wrappers for memory allocators. Called for both permanent 201 * and temporary boot memory allocations. We have to track which allocator 202 * (boot or kmem) was used so that we know how to free. 203 */ 204 void * 205 bkmem_alloc(size_t size) 206 { 207 /* allocate from boot scratch memory */ 208 void *addr; 209 210 if (_kmem_ready) 211 return (kobj_alloc(size, 0)); 212 213 /* 214 * Remember the highest BOP_ALLOC allocated address and don't free 215 * anything below it. 216 */ 217 addr = BOP_ALLOC(ops, 0, size, 0); 218 if (scratch_max < (uintptr_t)addr + size) 219 scratch_max = (uintptr_t)addr + size; 220 return (addr); 221 } 222 223 /*ARGSUSED*/ 224 void 225 bkmem_free(void *p, size_t size) 226 { 227 /* 228 * Free only if it's not boot scratch memory. 229 */ 230 if ((uintptr_t)p >= scratch_max) 231 kobj_free(p, size); 232 } 233 234 /*PRINTFLIKE1*/ 235 void 236 kobj_printf(char *fmt, ...) 237 { 238 va_list adx; 239 240 va_start(adx, fmt); 241 _kobj_printf(ops, fmt, adx); 242 va_end(adx); 243 } 244