1 /*        $NetBSD: ofhandlers.c,v 1.6 2013/07/02 11:59:46 joerg Exp $ */
2 
3 /*-
4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/ioctl.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include <dev/ofw/openfirmio.h>
42 
43 #include "defs.h"
44 
45 extern    char *path_openfirm;
46 extern    int eval;
47 extern    int verbose;
48 
49 static    char err_str[BUFSIZE];
50 
51 static    void of_notsupp(const struct extabent *, struct ofiocdesc *, char *);
52 static    void of_uint32h(const struct extabent *, struct ofiocdesc *, char *);
53 static    void of_uint32d(const struct extabent *, struct ofiocdesc *, char *);
54 
55 /*
56  * There are several known fields that I either don't know how to
57  * deal with or require special treatment.
58  */
59 static    const struct extabent ofextab[] = {
60           { "security-password",                  of_notsupp },
61           { "security-mode",            of_notsupp },
62           { "oem-logo",                           of_notsupp },
63           { "oem-banner",                         of_notsupp },
64           { "real-base",                          of_uint32h },
65           { "real-size",                          of_uint32h },
66           { "load-base",                          of_uint32h },
67           { "virt-base",                          of_uint32h },
68           { "virt-size",                          of_uint32h },
69           { "screen-#columns",                    of_uint32d },
70           { "screen-#rows",             of_uint32d },
71           { "selftest-#megs",           of_uint32d },
72           { NULL,                                 of_notsupp },
73 };
74 
75 #define BARF(str1, str2) {                                                      \
76           snprintf(err_str, sizeof err_str, "%s: %s", (str1), (str2));          \
77           ++eval;                                                                         \
78           return (err_str);                                                     \
79 };
80 
81 void
of_action(char * keyword,char * arg)82 of_action(char *keyword, char *arg)
83 {
84           char      *cp;
85 
86           if ((cp = of_handler(keyword, arg)) != NULL)
87                     warnx("%s", cp);
88           return;
89 }
90 
91 char *
of_handler(char * keyword,char * arg)92 of_handler(char *keyword, char *arg)
93 {
94           struct ofiocdesc ofio;
95           const struct extabent *ex;
96           char ofio_buf[BUFSIZE];
97           int fd, optnode;
98 
99           if ((fd = open(path_openfirm, arg ? O_RDWR : O_RDONLY, 0640)) < 0)
100                     BARF(path_openfirm, strerror(errno));
101 
102           /* Check to see if it's a special-case keyword. */
103           for (ex = ofextab; ex->ex_keyword != NULL; ++ex)
104                     if (strcmp(ex->ex_keyword, keyword) == 0)
105                               break;
106 
107           if (ioctl(fd, OFIOCGETOPTNODE, (char *)&optnode) < 0) {
108                     (void)close(fd);
109                     BARF("OFIOCGETOPTNODE", strerror(errno));
110           }
111 
112           memset(&ofio_buf[0], 0, sizeof(ofio_buf));
113           memset(&ofio, 0, sizeof(ofio));
114           ofio.of_nodeid = optnode;
115           ofio.of_name = keyword;
116           ofio.of_namelen = strlen(ofio.of_name);
117 
118           if (arg) {
119                     if (verbose) {
120                               printf("old: ");
121 
122                               ofio.of_buf = &ofio_buf[0];
123                               ofio.of_buflen = sizeof(ofio_buf);
124                               if (ioctl(fd, OFIOCGET, (char *)&ofio) < 0) {
125                                         (void)close(fd);
126                                         BARF("OFIOCGET", strerror(errno));
127                               }
128 
129                               if (ofio.of_buflen <= 0) {
130                                         printf("nothing available for %s\n", keyword);
131                                         goto out;
132                               }
133 
134                               if (ex->ex_keyword != NULL)
135                                         (*ex->ex_handler)(ex, &ofio, NULL);
136                               else
137                                         printf("%s\n", ofio.of_buf);
138                     }
139  out:
140                     if (ex->ex_keyword != NULL)
141                               (*ex->ex_handler)(ex, &ofio, arg);
142                     else {
143                               ofio.of_buf = arg;
144                               ofio.of_buflen = strlen(arg);
145                     }
146 
147                     if (ioctl(fd, OFIOCSET, (char *)&ofio) < 0) {
148                               (void)close(fd);
149                               BARF("invalid keyword", keyword);
150                     }
151 
152                     if (verbose) {
153                               printf("new: ");
154                               if (ex->ex_keyword != NULL)
155                                         (*ex->ex_handler)(ex, &ofio, NULL);
156                               else
157                                         printf("%s\n", ofio.of_buf);
158                     }
159           } else {
160                     ofio.of_buf = &ofio_buf[0];
161                     ofio.of_buflen = sizeof(ofio_buf);
162                     if (ioctl(fd, OFIOCGET, (char *)&ofio) < 0) {
163                               (void)close(fd);
164                               BARF("OFIOCGET", strerror(errno));
165                     }
166 
167                     if (ofio.of_buflen <= 0) {
168                               (void)snprintf(err_str, sizeof err_str,
169                                   "nothing available for %s", keyword);
170                               return (err_str);
171                     }
172 
173                     if (ex->ex_keyword != NULL)
174                               (*ex->ex_handler)(ex, &ofio, NULL);
175                     else
176                               printf("%s=%s\n", keyword, ofio.of_buf);
177           }
178 
179           (void)close(fd);
180           return (NULL);
181 }
182 
183 /* ARGSUSED */
184 static void
of_notsupp(const struct extabent * exent,struct ofiocdesc * ofiop,char * arg)185 of_notsupp(const struct extabent *exent, struct ofiocdesc *ofiop, char *arg)
186 {
187 
188           warnx("property `%s' not yet supported", exent->ex_keyword);
189 }
190 
191 static void
of_uint32h(const struct extabent * exent,struct ofiocdesc * ofiop,char * arg)192 of_uint32h(const struct extabent *exent, struct ofiocdesc *ofiop, char *arg)
193 {
194 
195           printf("%s=0x%08x\n", exent->ex_keyword, *(uint32_t *)ofiop->of_buf);
196 }
197 
198 static void
of_uint32d(const struct extabent * exent,struct ofiocdesc * ofiop,char * arg)199 of_uint32d(const struct extabent *exent, struct ofiocdesc *ofiop, char *arg)
200 {
201 
202           printf("%s=%d\n", exent->ex_keyword, *(uint32_t *)ofiop->of_buf);
203 }
204 
205 /*
206  * XXX: This code is quite ugly.  You have been warned.
207  * (Really!  This is the only way I could get it to work!)
208  */
209 void
of_dump(void)210 of_dump(void)
211 {
212           struct ofiocdesc ofio1, ofio2;
213           const struct extabent *ex;
214           char buf1[BUFSIZE], buf2[BUFSIZE], buf3[BUFSIZE], buf4[BUFSIZE];
215           int fd, optnode;
216 
217           if ((fd = open(path_openfirm, O_RDONLY, 0640)) < 0)
218                     err(1, "open: %s", path_openfirm);
219 
220           if (ioctl(fd, OFIOCGETOPTNODE, (char *)&optnode) < 0)
221                     err(1, "OFIOCGETOPTNODE");
222 
223           memset(&ofio1, 0, sizeof(ofio1));
224 
225           /* This will grab the first property name from OPIOCNEXTPROP. */
226           memset(buf1, 0, sizeof(buf1));
227           memset(buf2, 0, sizeof(buf2));
228 
229           ofio1.of_nodeid = ofio2.of_nodeid = optnode;
230 
231           ofio1.of_name = buf1;
232           ofio1.of_buf = buf2;
233 
234           ofio2.of_name = buf3;
235           ofio2.of_buf = buf4;
236 
237           /*
238            * For reference: ofio1 is for obtaining the name.  Pass the
239            * name of the last property read in of_name, and the next one
240            * will be returned in of_buf.  To get the first name, pass
241            * an empty string.  There are no more properties when an
242            * empty string is returned.
243            *
244            * ofio2 is for obtaining the value associated with that name.
245            * For some crazy reason, it seems as if we need to do all
246            * of that gratuitious zapping and copying.  *sigh*
247            */
248           for (;;) {
249                     ofio1.of_namelen = strlen(ofio1.of_name);
250                     ofio1.of_buflen = sizeof(buf2);
251 
252                     if (ioctl(fd, OFIOCNEXTPROP, (char *)&ofio1) < 0) {
253                               close(fd);
254                               return;
255                               /* err(1, "ioctl: OFIOCNEXTPROP"); */
256                     }
257 
258                     /*
259                      * The name of the property we wish to get the
260                      * value for has been stored in the value field
261                      * of ofio1.  If the length of the name is 0, there
262                      * are no more properties left.
263                      */
264                     strcpy(ofio2.of_name, ofio1.of_buf);    /* XXX strcpy is safe */
265                     ofio2.of_namelen = strlen(ofio2.of_name);
266 
267                     if (ofio2.of_namelen == 0) {
268                               (void)close(fd);
269                               return;
270                     }
271 
272                     memset(ofio2.of_buf, 0, sizeof(buf4));
273                     ofio2.of_buflen = sizeof(buf4);
274 
275                     if (ioctl(fd, OFIOCGET, (char *)&ofio2) < 0)
276                               err(1, "ioctl: OFIOCGET");
277 
278                     for (ex = ofextab; ex->ex_keyword != NULL; ++ex)
279                               if (strcmp(ex->ex_keyword, ofio2.of_name) == 0)
280                                         break;
281 
282                     if (ex->ex_keyword != NULL)
283                               (*ex->ex_handler)(ex, &ofio2, NULL);
284                     else
285                               printf("%s=%s\n", ofio2.of_name, ofio2.of_buf);
286 
287                     /*
288                      * Place the name of the last read value back into
289                      * ofio1 so that we may obtain the next name.
290                      */
291                     memset(ofio1.of_name, 0, sizeof(buf1));
292                     memset(ofio1.of_buf, 0, sizeof(buf2));
293                     strcpy(ofio1.of_name, ofio2.of_name);   /* XXX strcpy is safe */
294           }
295           /* NOTREACHED */
296 }
297