]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/imageboot.c
2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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 #include <kern/assert.h>
40 #include <pexpert/pexpert.h>
42 extern struct filedesc filedesc0
;
44 extern int (*mountroot
)(void);
45 extern char rootdevice
[];
47 #define DEBUG_IMAGEBOOT 0
50 #define DBG_TRACE(...) printf(__VA_ARGS__)
52 #define DBG_TRACE(...) do {} while(0)
55 extern int di_root_image(const char *path
, char devname
[], dev_t
*dev_p
);
56 static boolean_t
imageboot_setup_new(void);
58 #define kIBFilePrefix "file://"
60 __private_extern__
int
61 imageboot_format_is_valid(const char *root_path
)
63 return (strncmp(root_path
, kIBFilePrefix
,
64 strlen(kIBFilePrefix
)) == 0);
68 vnode_get_and_drop_always(vnode_t vp
)
75 __private_extern__
int
76 imageboot_needed(void)
79 char *root_path
= NULL
;
81 DBG_TRACE("%s: checking for presence of root path\n", __FUNCTION__
);
83 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
84 if (root_path
== NULL
)
85 panic("%s: M_NAMEI zone exhausted", __FUNCTION__
);
87 /* Check for first layer */
88 if (!(PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) ||
89 PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) ||
90 PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
))) {
94 /* Sanity-check first layer */
95 if (imageboot_format_is_valid(root_path
)) {
96 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
);
103 /* Check for second layer */
104 if (!(PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) ||
105 PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
))) {
109 /* Sanity-check second layer */
110 if (imageboot_format_is_valid(root_path
)) {
111 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
);
113 panic("%s: Invalid URL scheme for %s\n",
114 __FUNCTION__
, root_path
);
118 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
125 * Swaps in new root filesystem based on image path.
126 * Current root filesystem is removed from mount list and
127 * tagged MNTK_BACKS_ROOT, MNT_ROOTFS is cleared on it, and
128 * "rootvnode" is reset. Root vnode of currentroot filesystem
129 * is returned with usecount (no iocount).
131 __private_extern__
int
132 imageboot_mount_image(const char *root_path
, int height
)
136 vnode_t old_rootvnode
= NULL
;
140 error
= di_root_image(root_path
, rootdevice
, &dev
);
142 panic("%s: di_root_image failed: %d\n", __FUNCTION__
, error
);
147 printf("%s: root device 0x%x\n", __FUNCTION__
, rootdev
);
148 error
= vfs_mountroot();
150 panic("vfs_mountroot() failed.\n");
154 * Get the vnode for '/'.
155 * Set fdp->fd_fd.fd_cdir to reference it.
157 if (VFS_ROOT(TAILQ_LAST(&mountlist
,mntlist
), &newdp
, vfs_context_kernel()))
158 panic("%s: cannot find root vnode", __FUNCTION__
);
160 if (rootvnode
!= NULL
) {
161 /* remember the old rootvnode, but remove it from mountlist */
164 old_rootvnode
= rootvnode
;
165 old_rootfs
= rootvnode
->v_mount
;
167 mount_list_remove(old_rootfs
);
169 mount_lock(old_rootfs
);
170 #ifdef CONFIG_IMGSRC_ACCESS
171 old_rootfs
->mnt_kern_flag
|= MNTK_BACKS_ROOT
;
172 #endif /* CONFIG_IMGSRC_ACCESS */
173 old_rootfs
->mnt_flag
&= ~MNT_ROOTFS
;
174 mount_unlock(old_rootfs
);
177 /* switch to the new rootvnode */
180 new_rootfs
= rootvnode
->v_mount
;
181 mount_lock(new_rootfs
);
182 new_rootfs
->mnt_flag
|= MNT_ROOTFS
;
183 mount_unlock(new_rootfs
);
187 filedesc0
.fd_cdir
= newdp
;
188 DBG_TRACE("%s: root switched\n", __FUNCTION__
);
190 if (old_rootvnode
!= NULL
) {
191 #ifdef CONFIG_IMGSRC_ACCESS
192 if (height
>= 0 && PE_imgsrc_mount_supported()) {
193 imgsrc_rootvnodes
[height
] = old_rootvnode
;
195 vnode_get_and_drop_always(old_rootvnode
);
198 height
= 0; /* keep the compiler from complaining */
199 vnode_get_and_drop_always(old_rootvnode
);
200 #endif /* CONFIG_IMGSRC_ACCESS */
206 imageboot_setup_new()
209 char *root_path
= NULL
;
211 boolean_t done
= FALSE
;
213 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
214 assert(root_path
!= NULL
);
216 if(PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
) == TRUE
) {
217 printf("%s: container image url is %s\n", __FUNCTION__
, root_path
);
218 error
= imageboot_mount_image(root_path
, height
);
220 panic("Failed to mount container image.");
226 if (PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) == FALSE
) {
228 panic("%s specified without %s?\n", IMAGEBOOT_CONTAINER_ARG
, IMAGEBOOT_ROOT_ARG
);
234 printf("%s: root image url is %s\n", __FUNCTION__
, root_path
);
236 error
= imageboot_mount_image(root_path
, height
);
238 panic("Failed to mount root image.");
244 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
248 __private_extern__
void
252 char *root_path
= NULL
;
254 DBG_TRACE("%s: entry\n", __FUNCTION__
);
256 if (rootvnode
== NULL
) {
257 panic("imageboot_setup: rootvnode is NULL.");
261 * New boot-arg scheme:
262 * root-dmg : the dmg that will be the root filesystem.
263 * container-dmg : an optional dmg that contains the root-dmg.
265 if (imageboot_setup_new()) {
269 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
270 assert(root_path
!= NULL
);
273 * Look for outermost disk image to root from. If we're doing a nested boot,
274 * there's some sense in which the outer image never needs to be the root filesystem,
275 * but it does need very similar treatment: it must not be unmounted, needs a fake
276 * device vnode created for it, and should not show up in getfsstat() until exposed
277 * with MNT_IMGSRC. We just make it the temporary root.
279 if((PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) == FALSE
) &&
280 (PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) == FALSE
)) {
281 panic("%s: no valid path to image.\n", __FUNCTION__
);
284 printf("%s: root image url is %s\n", __FUNCTION__
, root_path
);
286 error
= imageboot_mount_image(root_path
, 0);
288 panic("Failed on first stage of imageboot.");
292 * See if we are rooting from a nested image
294 if(PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) == FALSE
) {
298 printf("%s: second level root image url is %s\n", __FUNCTION__
, root_path
);
301 * If we fail to set up second image, it's not a given that we
302 * can safely root off the first.
304 error
= imageboot_mount_image(root_path
, 1);
306 panic("Failed on second stage of imageboot.");
310 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
312 DBG_TRACE("%s: exit\n", __FUNCTION__
);