1 /* $OpenBSD: if_prom.c,v 1.9 2023/01/16 07:29:35 deraadt Exp $ */
2 /* $NetBSD: if_prom.c,v 1.9 1997/04/06 08:41:26 cgd Exp $ */
3
4 /*
5 * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved.
6 * Copyright (c) 1993 Adam Glass. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Adam Glass.
19 * 4. The name of the Author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36
37 #include <netinet/in.h>
38
39 #include <include/rpb.h>
40 #include <include/prom.h>
41
42 #include <lib/libkern/libkern.h>
43 #include <lib/libsa/netif.h>
44 #include <lib/libsa/stand.h>
45
46 #include "stand/bbinfo.h"
47
48 int prom_match(struct netif *, void *);
49 int prom_probe(struct netif *, void *);
50 void prom_init(struct iodesc *, void *);
51 int prom_get(struct iodesc *, void *, size_t, time_t);
52 int prom_put(struct iodesc *, void *, size_t);
53 void prom_end(struct netif *);
54
55 extern struct netif_stats prom_stats[];
56
57 struct netif_dif prom_ifs[] = {
58 /* dif_unit dif_nsel dif_stats dif_private */
59 { 0, 1, &prom_stats[0], 0, },
60 };
61
62 struct netif_stats prom_stats[nitems(prom_ifs)];
63
64 struct netbbinfo netbbinfo = {
65 0xfeedbabedeadbeef, /* magic number */
66 0, /* set */
67 0, 0, 0, 0, 0, 0, /* ether address */
68 0, /* force */
69 { 0, }, /* pad2 */
70 0, /* cksum */
71 0xfeedbeefdeadbabe, /* magic number */
72 };
73
74 struct netif_driver prom_netif_driver = {
75 "prom", /* netif_bname */
76 prom_match, /* netif_match */
77 prom_probe, /* netif_probe */
78 prom_init, /* netif_init */
79 prom_get, /* netif_get */
80 prom_put, /* netif_put */
81 prom_end, /* netif_end */
82 prom_ifs, /* netif_ifs */
83 nitems(prom_ifs) /* netif_nifs */
84 };
85
86 int netfd, broken_firmware;
87
88 int
prom_match(struct netif * nif,void * machdep_hint)89 prom_match(struct netif *nif, void *machdep_hint)
90 {
91
92 return (1);
93 }
94
95 int
prom_probe(struct netif * nif,void * machdep_hint)96 prom_probe(struct netif *nif, void *machdep_hint)
97 {
98
99 return 0;
100 }
101
102 int
prom_put(struct iodesc * desc,void * pkt,size_t len)103 prom_put(struct iodesc *desc, void *pkt, size_t len)
104 {
105
106 prom_write(netfd, len, pkt, 0);
107
108 return len;
109 }
110
111
112 int
prom_get(struct iodesc * desc,void * pkt,size_t len,time_t timeout)113 prom_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
114 {
115 prom_return_t ret;
116 time_t t;
117 ssize_t cc;
118 char hate[2000];
119
120 t = getsecs();
121 cc = 0;
122 while (((getsecs() - t) < timeout) && !cc) {
123 if (broken_firmware)
124 ret.bits = prom_read(netfd, 0, hate, 0);
125 else
126 ret.bits = prom_read(netfd, sizeof hate, hate, 0);
127 if (ret.u.status == 0)
128 cc = ret.u.retval;
129 }
130 if (broken_firmware)
131 cc = lmin(cc, len);
132 else
133 cc = len;
134 bcopy(hate, pkt, cc);
135
136 return cc;
137 }
138
139 extern char *strchr();
140 void halt(void);
141 const char *ether_sprintf(const u_char *);
142
143 void
prom_init(struct iodesc * desc,void * machdep_hint)144 prom_init(struct iodesc *desc, void *machdep_hint)
145 {
146 prom_return_t ret;
147 char devname[64];
148 int devlen, i, netbbinfovalid;
149 char *enet_addr;
150 u_int64_t *qp, csum;
151
152 broken_firmware = 0;
153
154 csum = 0;
155 for (i = 0, qp = (u_int64_t *)&netbbinfo;
156 i < (sizeof netbbinfo / sizeof (u_int64_t)); i++, qp++)
157 csum += *qp;
158 netbbinfovalid = (csum == 0);
159 if (netbbinfovalid)
160 netbbinfovalid = netbbinfo.set;
161
162 #if 0
163 printf("netbbinfo ");
164 if (!netbbinfovalid)
165 printf("invalid\n");
166 else
167 printf("valid: force = %d, ea = %s\n", netbbinfo.force,
168 ether_sprintf(netbbinfo.ether_addr));
169 #endif
170
171 ret.bits = prom_getenv(PROM_E_BOOTED_DEV, devname, sizeof(devname));
172 devlen = ret.u.retval;
173
174 /* Ethernet address is the 9th component of the booted_dev string. */
175 enet_addr = devname;
176 for (i = 0; i < 8; i++) {
177 enet_addr = strchr(enet_addr, ' ');
178 if (enet_addr == NULL) {
179 printf("boot: boot device name does not contain ethernet address.\n");
180 goto punt;
181 }
182 enet_addr++;
183 }
184 if (enet_addr != NULL) {
185 int hv, lv;
186
187 #define dval(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
188 (((c) >= 'A' && (c) <= 'F') ? (10 + (c) - 'A') : \
189 (((c) >= 'a' && (c) <= 'f') ? (10 + (c) - 'a') : -1)))
190
191 for (i = 0; i < 6; i++) {
192 hv = dval(*enet_addr); enet_addr++;
193 lv = dval(*enet_addr); enet_addr++;
194 enet_addr++;
195
196 if (hv == -1 || lv == -1) {
197 printf("boot: boot device name contains bogus ethernet address.\n");
198 goto punt;
199 }
200
201 desc->myea[i] = (hv << 4) | lv;
202 }
203 #undef dval
204 }
205
206 if (netbbinfovalid && netbbinfo.force) {
207 printf("boot: using hard-coded ethernet address (forced).\n");
208 bcopy(netbbinfo.ether_addr, desc->myea, sizeof desc->myea);
209 }
210
211 gotit:
212 printf("boot: ethernet address: %s\n", ether_sprintf(desc->myea));
213
214 ret.bits = prom_open((u_int64_t)devname, devlen + 1);
215 if (ret.u.status) {
216 printf("prom_init: open failed: %d\n", ret.u.status);
217 goto reallypunt;
218 }
219 netfd = ret.u.retval;
220 return;
221
222 punt:
223 broken_firmware = 1;
224 if (netbbinfovalid) {
225 printf("boot: using hard-coded ethernet address.\n");
226 bcopy(netbbinfo.ether_addr, desc->myea, sizeof desc->myea);
227 goto gotit;
228 }
229
230 reallypunt:
231 printf("\n");
232 printf("Boot device name was: \"%s\"\n", devname);
233 printf("\n");
234 printf("Your firmware may be too old to network-boot OpenBSD/alpha,\n");
235 printf("or you might have to hard-code an ethernet address into\n");
236 printf("your network boot block with setnetbootinfo(8).\n");
237 halt();
238 }
239
240 void
prom_end(struct netif * nif)241 prom_end(struct netif *nif)
242 {
243
244 prom_close(netfd);
245 }
246