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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include "benv.h" 28 #include <sys/sunddi.h> 29 #include <sys/ddi_impldefs.h> 30 #include <sys/openpromio.h> 31 #include <stdio.h> 32 33 static int getpropval(struct openpromio *opp, char *prop); 34 35 static char *promdev = "/dev/openprom"; 36 static int prom_fd; 37 static char *mfail = "malloc"; 38 39 /* 40 * 128 is the size of the largest (currently) property name 41 * 16384 - MAXPROPSIZE - sizeof (int) is the size of the largest 42 * (currently) property value that is allowed. 43 * the sizeof (u_int) is from struct openpromio 44 */ 45 46 #define MAXPROPSIZE 128 47 #define MAXVALSIZE (16384 - MAXPROPSIZE - sizeof (u_int)) 48 #define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (u_int)) 49 #define MINVALSIZE (4 * sizeof (u_long)) 50 #define MINBUFSIZE (MINVALSIZE + sizeof (u_long)) 51 52 typedef union { 53 char buf[BUFSIZE]; 54 struct openpromio opp; 55 } Oppbuf; 56 57 typedef union { 58 char buf[MINVALSIZE + sizeof (u_int)]; 59 struct openpromio opp; 60 } Oppbuf_small; 61 62 static Oppbuf oppbuf; 63 64 static unsigned long 65 next(unsigned long id) 66 { 67 Oppbuf_small oppbuf; 68 struct openpromio *opp = &(oppbuf.opp); 69 unsigned long *ip = (unsigned long *)(opp->oprom_array); 70 71 memset(oppbuf.buf, 0, MINBUFSIZE); 72 opp->oprom_size = MINVALSIZE; 73 *ip = id; 74 if (ioctl(prom_fd, OPROMNEXT, opp) < 0) 75 return (0); 76 return (*(unsigned long *)opp->oprom_array); 77 } 78 79 static unsigned long 80 child(unsigned long id) 81 { 82 Oppbuf_small oppbuf; 83 struct openpromio *opp = &(oppbuf.opp); 84 unsigned long *ip = (unsigned long *)(opp->oprom_array); 85 86 memset(oppbuf.buf, 0, MINBUFSIZE); 87 opp->oprom_size = MINVALSIZE; 88 *ip = id; 89 if (ioctl(prom_fd, OPROMCHILD, opp) < 0) 90 return (0); 91 return (*(unsigned long *)opp->oprom_array); 92 } 93 94 /* 95 * Find a node by name from the prom device tree. 96 * Return the id or 0 if it is not found. 97 */ 98 static unsigned long 99 prom_findnode_byname(unsigned long id, char *name) 100 { 101 struct openpromio *opp = &(oppbuf.opp); 102 unsigned long nid; 103 104 if (id == 0) 105 return (0); 106 if (!getpropval(opp, "name")) 107 return (0); 108 if (strcmp(opp->oprom_array, name) == 0) 109 return (id); 110 if (nid = prom_findnode_byname(child(id), name)) 111 return (nid); 112 if (nid = prom_findnode_byname(next(id), name)) 113 return (nid); 114 return (0); 115 } 116 117 /* 118 * Make the current prom node be the rootnode and return its id. 119 */ 120 static unsigned long 121 prom_rootnode() 122 { 123 return (next(0)); 124 } 125 126 static int 127 getpropval(struct openpromio *opp, char *prop) 128 { 129 opp->oprom_size = MAXVALSIZE; 130 131 (void) strlcpy(opp->oprom_array, prop, MAXPROPSIZE); 132 if (ioctl(prom_fd, OPROMGETPROP, opp) < 0) 133 return (0); 134 if (opp->oprom_size == 0) 135 return (0); 136 return (1); 137 } 138 139 static int 140 getnextprop(struct openpromio *opp, char *prop) 141 { 142 opp->oprom_size = MAXVALSIZE; 143 144 (void) strlcpy(opp->oprom_array, prop, MAXPROPSIZE); 145 if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0) 146 return (0); 147 if (opp->oprom_size == 0) 148 return (0); 149 return (1); 150 } 151 152 char * 153 getbootcmd(void) 154 { 155 struct openpromio *opp = &(oppbuf.opp); 156 opp->oprom_size = MAXVALSIZE; 157 if (ioctl(prom_fd, OPROMGETBOOTPATH, opp) < 0) 158 return (NULL); 159 return (opp->oprom_array); 160 } 161 162 /* 163 * Get a pointer to the requested property from the current node. 164 * The property is stored in static storage and the returned pointer 165 * points into the static storage. The property length is placed in 166 * the location pointed to by the third argument. 167 */ 168 static unsigned char * 169 prom_getprop(char *prop, int *lenp) 170 { 171 struct openpromio *opp = &(oppbuf.opp); 172 173 if (!getpropval(opp, prop)) 174 return (NULL); 175 *lenp = opp->oprom_size; 176 return ((unsigned char *)opp->oprom_array); 177 } 178 179 static unsigned char * 180 prom_nextprop(char *prop) 181 { 182 struct openpromio *opp = &(oppbuf.opp); 183 184 if (!getnextprop(opp, prop)) 185 return ((unsigned char *)0); 186 return ((unsigned char *)opp->oprom_array); 187 } 188 189 ddi_prop_t * 190 get_proplist(char *name) 191 { 192 ddi_prop_t *plist, *npp, *plast; 193 char *curprop, *newprop; 194 unsigned char *propval; 195 unsigned long id; 196 197 plist = NULL; 198 plast = NULL; 199 id = prom_findnode_byname(prom_rootnode(), name); 200 if (id == 0) 201 return (plist); 202 curprop = ""; 203 while (newprop = (char *)prom_nextprop(curprop)) { 204 curprop = strdup(newprop); 205 npp = (ddi_prop_t *)malloc(sizeof (ddi_prop_t)); 206 if (npp == 0) 207 exit(_error(PERROR, mfail)); 208 propval = prom_getprop(curprop, &npp->prop_len); 209 npp->prop_name = curprop; 210 if (propval != NULL) { 211 npp->prop_val = (char *)malloc(npp->prop_len); 212 if (npp->prop_val == 0) 213 exit(_error(PERROR, mfail)); 214 memcpy(npp->prop_val, propval, npp->prop_len); 215 } else 216 npp->prop_val = NULL; 217 npp->prop_next = NULL; 218 if (plast == NULL) { 219 plist = npp; 220 } else { 221 plast->prop_next = npp; 222 } 223 plast = npp; 224 } 225 return (plist); 226 } 227 228 caddr_t 229 get_propval(char *name, char *node) 230 { 231 ddi_prop_t *prop, *plist; 232 233 if ((plist = get_proplist(node)) == NULL) 234 return (NULL); 235 236 for (prop = plist; prop != NULL; prop = prop->prop_next) 237 if (strcmp(prop->prop_name, name) == 0) 238 return (prop->prop_val); 239 240 return (NULL); 241 } 242 243 void 244 get_kbenv(void) 245 { 246 if ((prom_fd = open(promdev, O_RDONLY)) < 0) { 247 exit(_error(PERROR, "prom open failed")); 248 } 249 } 250 251 void 252 close_kbenv(void) 253 { 254 (void) close(prom_fd); 255 } 256