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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/param.h>
30 #include <sys/idprom.h>
31 #include <sys/promif.h>
32 #include <sys/salib.h>
33 
34 #include <sys/platnames.h>
35 
36 /*
37  * This source is (and should be ;-) shared between the boot blocks
38  * and the boot programs.  So if you change it, be sure to test them all!
39  */
40 
41 #define	MAXNMLEN	1024		/* # of chars in a property */
42 
43 /*
44  * Supplied by modpath.c
45  *
46  * Making these externs here allows all sparc machines to share
47  * get_impl_arch_name().
48  */
49 extern char *default_name;
50 extern char *default_path;
51 
52 enum ia_state_mach {
53 	STATE_NAME,
54 	STATE_COMPAT_INIT,
55 	STATE_COMPAT,
56 	STATE_DEFAULT,
57 	STATE_FINI
58 };
59 
60 /*
61  * Return the implementation architecture name (uname -i) for this platform.
62  *
63  * Use the named rootnode property to determine the iarch.
64  */
65 static char *
66 get_impl_arch_name(enum ia_state_mach *state, int use_default)
67 {
68 	static char iarch[MAXNMLEN];
69 	static int len;
70 	static char *ia;
71 
72 	pnode_t n;
73 	char *cp;
74 	char *namename;
75 
76 newstate:
77 	switch (*state) {
78 	case STATE_NAME:
79 		*state = STATE_COMPAT_INIT;
80 		namename = OBP_NAME;
81 		n = (pnode_t)prom_rootnode();
82 		len = prom_getproplen(n, namename);
83 		if (len <= 0 || len >= MAXNMLEN)
84 			goto newstate;
85 		(void) prom_getprop(n, namename, iarch);
86 		iarch[len] = '\0';	/* fix broken clones */
87 		ia = iarch;
88 		break;
89 
90 	case STATE_COMPAT_INIT:
91 		*state = STATE_COMPAT;
92 		namename = OBP_COMPATIBLE;
93 		n = (pnode_t)prom_rootnode();
94 		len = prom_getproplen(n, namename);
95 		if (len <= 0 || len >= MAXNMLEN) {
96 			*state = STATE_DEFAULT;
97 			goto newstate;
98 		}
99 		(void) prom_getprop(n, namename, iarch);
100 		iarch[len] = '\0';	/* ensure null termination */
101 		ia = iarch;
102 		break;
103 
104 	case STATE_COMPAT:
105 		/*
106 		 * Advance 'ia' to point to next string in
107 		 * compatible property array (if any).
108 		 */
109 		while (*ia++)
110 			;
111 		if ((ia - iarch) >= len) {
112 			*state = STATE_DEFAULT;
113 			goto newstate;
114 		}
115 		break;
116 
117 	case STATE_DEFAULT:
118 		*state = STATE_FINI;
119 		if (!use_default || default_name == NULL)
120 			goto newstate;
121 		(void) strcpy(iarch, default_name);
122 		ia = iarch;
123 		break;
124 
125 	case STATE_FINI:
126 		return (NULL);
127 	}
128 
129 	/*
130 	 * Crush filesystem-awkward characters.  See PSARC/1992/170.
131 	 * (Convert the property to a sane directory name in UFS)
132 	 */
133 	for (cp = ia; *cp; cp++)
134 		if (*cp == '/' || *cp == ' ' || *cp == '\t')
135 			*cp = '_';
136 	return (ia);
137 }
138 
139 static void
140 make_platform_path(char *fullpath, char *iarch, char *filename)
141 {
142 	(void) strcpy(fullpath, "/platform/");
143 	(void) strcat(fullpath, iarch);
144 	if (filename != NULL) {
145 		(void) strcat(fullpath, "/");
146 		(void) strcat(fullpath, filename);
147 	}
148 }
149 
150 /*
151  * Generate impl_arch_name by searching the /platform hierarchy
152  * for a matching directory.  We are not looking for any particular
153  * file here, but for a directory hierarchy for the module path.
154  */
155 int
156 find_platform_dir(int (*isdirfn)(char *), char *iarch, int use_default)
157 {
158 	char fullpath[MAXPATHLEN];
159 	char *ia;
160 	enum ia_state_mach state = STATE_NAME;
161 
162 	/*
163 	 * Hunt the filesystem looking for a directory hierarchy.
164 	 */
165 	while ((ia = get_impl_arch_name(&state, use_default)) != NULL) {
166 		make_platform_path(fullpath, ia, NULL);
167 		if (((*isdirfn)(fullpath)) != 0) {
168 			(void) strcpy(iarch, ia);
169 			return (1);
170 		}
171 	}
172 	return (0);
173 }
174 
175 /*
176  * Search the /platform hierarchy looking for a particular file.
177  *
178  * impl_arch_name is given as an optional hint as to where the
179  * file might be found.
180  */
181 int
182 open_platform_file(
183 	char *filename,
184 	int (*openfn)(char *, void *),
185 	void *arg,
186 	char *fullpath,
187 	char *given_iarch)
188 {
189 	char *ia;
190 	int fd;
191 	enum ia_state_mach state = STATE_NAME;
192 
193 	/*
194 	 * First try the impl_arch_name hint.
195 	 *
196 	 * This is only here to support the -I flag to boot.
197 	 */
198 	if (given_iarch != NULL) {
199 		make_platform_path(fullpath, given_iarch, filename);
200 		return ((*openfn)(fullpath, arg));
201 	}
202 
203 	/*
204 	 * Hunt the filesystem for one that works ..
205 	 */
206 	while ((ia = get_impl_arch_name(&state, 1)) != NULL) {
207 		make_platform_path(fullpath, ia, filename);
208 		if ((fd = (*openfn)(fullpath, arg)) != -1)
209 			return (fd);
210 	}
211 
212 	return (-1);
213 }
214