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