xref: /openbsd/sys/arch/loongson/stand/boot/dev.c (revision 097a140d)
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
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
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
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
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