1/* 2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <sys/param.h> 30#include <sys/kernel.h> 31#include <sys/proc_internal.h> 32#include <sys/systm.h> 33#include <sys/systm.h> 34#include <sys/mount_internal.h> 35#include <sys/filedesc.h> 36#include <sys/vnode_internal.h> 37#include <sys/imageboot.h> 38 39#include <pexpert/pexpert.h> 40 41extern struct filedesc filedesc0; 42 43extern int (*mountroot)(void); 44extern char rootdevice[]; 45 46#define DEBUG_IMAGEBOOT 0 47 48#if DEBUG_IMAGEBOOT 49#define DBG_TRACE(...) printf(__VA_ARGS__) 50#else 51#define DBG_TRACE(...) do {} while(0) 52#endif 53 54extern int di_root_image(const char *path, char devname[], dev_t *dev_p); 55 56#define kIBFilePrefix "file://" 57 58int 59imageboot_needed(void) 60{ 61 int result = 0; 62 char *root_path = NULL; 63 64 DBG_TRACE("%s: checking for presence of root path\n", __FUNCTION__); 65 66 MALLOC_ZONE(root_path, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 67 if (root_path == NULL) 68 panic("%s: M_NAMEI zone exhausted", __FUNCTION__); 69 70 if(PE_parse_boot_argn("rp", root_path, MAXPATHLEN) == TRUE) { 71 /* Got it, now verify scheme */ 72 73 if (strncmp(root_path, kIBFilePrefix, 74 strlen(kIBFilePrefix)) == 0) { 75 DBG_TRACE("%s: Found %s\n", __FUNCTION__, root_path); 76 result = 1; 77 } else { 78 DBG_TRACE("%s: Invalid URL scheme for %s\n", 79 __FUNCTION__, root_path); 80 } 81 } 82 FREE_ZONE(root_path, MAXPATHLEN, M_NAMEI); 83 84 return (result); 85} 86 87 88/* 89 * We know there's an image. Attach it, and 90 * switch over to root off it 91 * 92 * NB: p is always kernproc 93 */ 94 95int 96imageboot_setup() 97{ 98 dev_t dev; 99 int error = 0; 100 char *root_path = NULL; 101 102 DBG_TRACE("%s: entry\n", __FUNCTION__); 103 104 MALLOC_ZONE(root_path, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 105 if (root_path == NULL) 106 return (ENOMEM); 107 108 if(PE_parse_boot_argn("rp", root_path, MAXPATHLEN) == FALSE) { 109 error = ENOENT; 110 goto done; 111 } 112 113 printf("%s: root image url is %s\n", __FUNCTION__, root_path); 114 error = di_root_image(root_path, rootdevice, &dev); 115 if(error) { 116 printf("%s: di_root_image failed: %d\n", __FUNCTION__, error); 117 goto done; 118 } 119 120 rootdev = dev; 121 mountroot = NULL; 122 printf("%s: root device 0x%x\n", __FUNCTION__, rootdev); 123 error = vfs_mountroot(); 124 125 if (error == 0 && rootvnode != NULL) { 126 struct vnode *tvp; 127 struct vnode *newdp; 128 129 /* 130 * Get the vnode for '/'. 131 * Set fdp->fd_fd.fd_cdir to reference it. 132 */ 133 if (VFS_ROOT(TAILQ_LAST(&mountlist,mntlist), &newdp, vfs_context_kernel())) 134 panic("%s: cannot find root vnode", __FUNCTION__); 135 136 vnode_ref(newdp); 137 vnode_put(newdp); 138 tvp = rootvnode; 139 vnode_rele(tvp); 140 filedesc0.fd_cdir = newdp; 141 rootvnode = newdp; 142 mount_list_lock(); 143 TAILQ_REMOVE(&mountlist, TAILQ_FIRST(&mountlist), mnt_list); 144 mount_list_unlock(); 145 mountlist.tqh_first->mnt_flag |= MNT_ROOTFS; 146 DBG_TRACE("%s: root switched\n", __FUNCTION__); 147 } 148done: 149 FREE_ZONE(root_path, MAXPATHLEN, M_NAMEI); 150 151 DBG_TRACE("%s: exit\n", __FUNCTION__); 152 153 return (error); 154} 155