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