1 /* $OpenBSD: dev.c,v 1.11 2020/12/09 18:10:19 krw Exp $ */
2
3 /*
4 * Copyright (c) 2010 Miodrag Vallat.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 /*-
19 * Copyright (c) 2003 The NetBSD Foundation, Inc.
20 * All rights reserved.
21 *
22 * This code is derived from software contributed to The NetBSD Foundation
23 * by Manuel Bouyer.
24 *
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions
27 * are met:
28 * 1. Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
35 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
38 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44 * POSSIBILITY OF SUCH DAMAGE.
45 */
46
47 #include <sys/param.h>
48 #include "libsa.h"
49 #include <sys/disklabel.h>
50 #include <machine/cpu.h>
51 #include <machine/pmon.h>
52
53 /*
54 * PMON I/O
55 */
56
57 char pmon_bootdev[1 + 256];
58
59 struct pmon_iodata {
60 int fd;
61 struct disklabel label;
62 off_t partoff;
63 off_t curpos;
64 };
65
66 int pmon_getdisklabel(struct pmon_iodata *pi);
67
68 int
pmon_iostrategy(void * f,int rw,daddr_t dblk,size_t size,void * buf,size_t * rsize)69 pmon_iostrategy(void *f, int rw, daddr_t dblk, size_t size, void *buf,
70 size_t *rsize)
71 {
72 struct pmon_iodata *pi = (struct pmon_iodata *)f;
73 off_t offs, pos;
74 int rc;
75
76 if (rsize != NULL)
77 *rsize = 0;
78 if (size == 0)
79 return 0;
80
81 if (rw != F_READ)
82 return EOPNOTSUPP;
83
84 offs = ((daddr_t)dblk + pi->partoff) * DEV_BSIZE;
85 if (offs != pi->curpos) {
86 pos = pmon_lseek(pi->fd, offs, 0 /* SEEK_SET */);
87 if (pos != offs)
88 return EINVAL;
89 }
90
91 /* note this expects size to fit in 32 bits */
92 rc = pmon_read(pi->fd, buf, size);
93 if (rc >= 0) {
94 pi->curpos += rc;
95 if (rsize != NULL)
96 *rsize = rc;
97 }
98
99 if (rc != size)
100 return EIO;
101 return 0;
102 }
103
104 int
pmon_ioopen(struct open_file * f,...)105 pmon_ioopen(struct open_file *f, ...)
106 {
107 static const u_char zero[8] = { 0 };
108 struct pmon_iodata *pi;
109 int rc;
110 va_list ap;
111 uint unit, part;
112
113 pi = alloc(sizeof *pi);
114 if (pi == NULL)
115 return ENOMEM;
116 bzero(pi, sizeof *pi);
117 f->f_devdata = pi;
118
119 va_start(ap, f);
120 unit = va_arg(ap, uint);
121 part = va_arg(ap, uint);
122 va_end(ap);
123
124 /*
125 * Open the raw device through PMON.
126 */
127
128 snprintf(pmon_bootdev, sizeof pmon_bootdev, "/dev/disk/%s%d",
129 f->f_dev->dv_name, unit);
130 rc = pmon_open(pmon_bootdev, 0 /* O_RDONLY */);
131 if (rc < 0)
132 return ENXIO;
133
134 pi->fd = rc;
135
136 /*
137 * Read disklabel.
138 */
139
140 if (pmon_getdisklabel(pi) != 0) {
141 pmon_ioclose(f);
142 return ENXIO;
143 }
144
145 if (part >= pi->label.d_npartitions) {
146 pmon_ioclose(f);
147 return EPART;
148 }
149
150 if (memcmp(pi->label.d_uid, zero, sizeof(pi->label.d_uid)) != 0) {
151 const u_char *duid = pi->label.d_uid;
152
153 snprintf(pmon_bootdev, sizeof(pmon_bootdev),
154 "bootduid=%02x%02x%02x%02x%02x%02x%02x%02x",
155 duid[0], duid[1], duid[2], duid[3],
156 duid[4], duid[5], duid[6], duid[7]);
157 }
158
159 pi->partoff = DL_GETPOFFSET(&pi->label.d_partitions[part]);
160 pi->curpos = 0;
161
162 return 0;
163 }
164
165 int
pmon_ioclose(struct open_file * f)166 pmon_ioclose(struct open_file *f)
167 {
168 struct pmon_iodata *pi;
169 int rc;
170
171 if (f->f_devdata != NULL) {
172 pi = (struct pmon_iodata *)f->f_devdata;
173 rc = pmon_close(pi->fd);
174 free(pi, sizeof *pi);
175 f->f_devdata = NULL;
176 } else
177 rc = 0;
178
179 return rc;
180 }
181
182 /*
183 * Read disk label from the device.
184 */
185 int
pmon_getdisklabel(struct pmon_iodata * pi)186 pmon_getdisklabel(struct pmon_iodata *pi)
187 {
188 char *msg;
189 int sector;
190 size_t rsize;
191 struct disklabel *lp = &pi->label;
192 char buf[DEV_BSIZE];
193
194 bzero(lp, sizeof *lp);
195
196 /*
197 * Find OpenBSD Partition in DOS partition table.
198 */
199 sector = 0;
200 if (pmon_iostrategy(pi, F_READ, DOSBBSECTOR, DEV_BSIZE, buf, &rsize))
201 return ENXIO;
202
203 if (*(u_int16_t *)&buf[DOSMBR_SIGNATURE_OFF] == DOSMBR_SIGNATURE) {
204 int i;
205 struct dos_partition *dp = (struct dos_partition *)buf;
206
207 /*
208 * Lookup OpenBSD slice. If there is none, go ahead
209 * and try to read the disklabel off sector #0.
210 */
211 memcpy(dp, &buf[DOSPARTOFF], NDOSPART * sizeof(*dp));
212 for (i = 0; i < NDOSPART; i++) {
213 if (dp[i].dp_typ == DOSPTYP_OPENBSD) {
214 sector = letoh32(dp[i].dp_start);
215 break;
216 }
217 }
218 }
219
220 if (pmon_iostrategy(pi, F_READ, sector + DOS_LABELSECTOR, DEV_BSIZE,
221 buf, &rsize))
222 return ENXIO;
223
224 if ((msg = getdisklabel(buf + LABELOFFSET, lp))) {
225 printf("getdisklabel: %s\n", msg);
226 return ENXIO;
227 }
228
229 return 0;
230 }
231