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 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27#include <sys/types.h>
28#include <sys/param.h>
29#include <sys/fcntl.h>
30#include <sys/obpdefs.h>
31#include <sys/reboot.h>
32#include <sys/promif.h>
33#include <sys/stat.h>
34#include <sys/bootvfs.h>
35#include <sys/platnames.h>
36#include <sys/salib.h>
37#include <sys/elf.h>
38#include <sys/link.h>
39#include <sys/auxv.h>
40#include <sys/boot_policy.h>
41#include <sys/boot_redirect.h>
42#include <sys/bootconf.h>
43#include <sys/boot.h>
44#include "boot_plat.h"
45#include "ramdisk.h"
46
47#define	SUCCESS		0
48#define	FAILURE		-1
49
50#ifdef DEBUG
51extern int debug = 0;
52#else
53static const int debug = 0;
54#endif
55
56#define	dprintf		if (debug) printf
57
58char		*def_boot_archive = "boot_archive";
59char		*def_miniroot = "miniroot";
60extern char	cmd_line_boot_archive[];
61
62extern int	openfile(char *filename);
63
64static int
65read_and_boot_ramdisk(int fd)
66{
67	struct stat	st;
68	caddr_t		virt;
69	size_t		size;
70	extern		ssize_t xread(int, char *, size_t);
71
72	if ((fstat(fd, &st) != 0) ||
73	    ((virt = create_ramdisk(RD_ROOTFS, st.st_size, NULL)) == NULL))
74		return (-1);
75
76	dprintf("reading boot archive ...\n");
77	if ((size = xread(fd, (char *)virt, st.st_size)) != st.st_size) {
78		(void) printf("Error reading boot archive, bytes read = %ld, "
79		    "filesize = %ld\n", (long)size, (long)st.st_size);
80		destroy_ramdisk(RD_ROOTFS);
81		return (-1);
82	}
83
84	boot_ramdisk(RD_ROOTFS);
85	/* NOT REACHED */
86	return (0);	/* to make cc happy */
87}
88
89
90static void
91post_mountroot_nfs(void)
92{
93	int	fd;
94	char	*fn;
95	char	tmpname[MAXPATHLEN];
96
97	for (;;) {
98		fn = NULL;
99		if (boothowto & RB_ASKNAME) {
100			char ctmpname[MAXPATHLEN];
101
102			fn = (cmd_line_boot_archive[0] != '\0') ?
103			    cmd_line_boot_archive : def_boot_archive;
104
105			/* Avoid buffer overrun */
106			(void) strncpy(tmpname, fn, strlen(fn)+1);
107			fn = tmpname;
108
109			printf("Enter filename [%s]: ", fn);
110			(void) cons_gets(ctmpname, sizeof (ctmpname));
111			if (ctmpname[0] != '\0') {
112				(void) strncpy(tmpname, ctmpname,
113				    strlen(ctmpname)+1);
114				fn = tmpname;
115			}
116		}
117
118		if (boothowto & RB_HALT) {
119			printf("Boot halted.\n");
120			prom_enter_mon();
121		}
122
123
124		if (fn != NULL) {
125			fd = openfile(fn);
126		} else if (cmd_line_boot_archive[0] != '\0') {
127			(void) strncpy(tmpname, cmd_line_boot_archive,
128			    strlen(cmd_line_boot_archive)+1);
129			fn = tmpname;
130			fd = openfile(fn);
131		} else {
132			(void) strncpy(tmpname, def_boot_archive,
133			    strlen(def_boot_archive)+1);
134			fn = tmpname;
135			if ((fd = openfile(fn)) == FAILURE) {
136				(void) strncpy(tmpname, def_miniroot,
137				    strlen(def_miniroot)+1);
138				fn = tmpname;
139				fd = openfile(fn);
140			}
141		}
142
143		if (fn != tmpname || tmpname[0] == '\0') {
144			printf("Possible buffer overrun, "
145			    "entering boot prompt\n");
146			prom_enter_mon();
147		}
148
149
150		if (fd == FAILURE) {
151			if (strncmp(fn, def_miniroot,
152			    strlen(def_miniroot)+1) != 0)
153				printf("cannot open %s\n", fn);
154			else
155				printf("cannot open neither %s nor %s\n",
156				    def_boot_archive, def_miniroot);
157		} else {
158			/*
159			 * this function does not return if successful.
160			 */
161			(void) read_and_boot_ramdisk(fd);
162
163			printf("boot failed\n");
164			(void) close(fd);
165		}
166		boothowto |= RB_ASKNAME;
167	}
168}
169
170
171/*
172 * bpath is the boot device path buffer.
173 * bargs is the boot arguments buffer.
174 */
175/*ARGSUSED*/
176int
177bootprog(char *bpath, char *bargs, boolean_t user_specified_filename)
178{
179	systype = set_fstype(v2path, bpath);
180
181	if (verbosemode) {
182		printf("device path '%s'\n", bpath);
183		if (strcmp(bpath, v2path) != 0)
184			printf("client path '%s'\n", v2path);
185	}
186
187	if (mountroot(bpath) != SUCCESS)
188		prom_panic("Could not mount filesystem.");
189
190	/*
191	 * kernname (default-name) might have changed if mountroot() called
192	 * boot_nfs_mountroot(), and it called set_default_filename().
193	 */
194	if (!user_specified_filename)
195		(void) strcpy(filename, kernname);
196
197	if (verbosemode)
198		printf("standalone = `%s', args = `%s'\n", filename, bargs);
199
200	set_client_bootargs(filename, bargs);
201
202	post_mountroot_nfs();
203
204	return (1);
205}
206