xref: /openbsd-src/sys/arch/loongson/stand/boot/dev.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: dev.c,v 1.3 2011/03/13 00:13:53 deraadt 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/types.h>
48 #include "libsa.h"
49 #include <sys/disklabel.h>
50 #include <machine/param.h>
51 #include <machine/cpu.h>
52 #include <machine/pmon.h>
53 
54 /*
55  * PMON I/O
56  */
57 
58 char	pmon_bootdev[1 + 256];
59 
60 struct pmon_iodata {
61 	int			fd;
62 	struct disklabel	label;
63 	off_t			partoff;
64 	off_t			curpos;
65 };
66 
67 int	pmon_getdisklabel(struct pmon_iodata *pi);
68 
69 int
70 pmon_iostrategy(void *f, int rw, daddr32_t dblk, size_t size, void *buf,
71     size_t *rsize)
72 {
73 	struct pmon_iodata *pi = (struct pmon_iodata *)f;
74 	off_t offs, pos;
75 	int rc;
76 
77 	*rsize = 0;
78 	if (size == 0)
79 		return 0;
80 
81 	if (rw != F_READ)
82 		return EOPNOTSUPP;
83 
84 	offs = ((daddr64_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 		*rsize = rc;
96 	} else
97 		*rsize = 0;
98 
99 	if (rc != size)
100 		return EIO;
101 	return 0;
102 }
103 
104 int
105 pmon_ioopen(struct open_file *f, ...)
106 {
107 	struct pmon_iodata *pi;
108 	int rc;
109 	va_list ap;
110 	uint unit, part;
111 
112 	pi = alloc(sizeof *pi);
113 	if (pi == NULL)
114 		return ENOMEM;
115 	bzero(pi, sizeof *pi);
116 	f->f_devdata = pi;
117 
118 	va_start(ap, f);
119 	unit = va_arg(ap, uint);
120 	part = va_arg(ap, uint);
121 	va_end(ap);
122 
123 	/*
124 	 * Open the raw device through PMON.
125 	 */
126 
127 	snprintf(pmon_bootdev, sizeof pmon_bootdev, "/dev/disk/%s%d",
128 	    f->f_dev->dv_name, unit);
129 	rc = pmon_open(pmon_bootdev, 0 /* O_RDONLY */);
130 	if (rc < 0)
131 		return ENXIO;
132 
133 	pi->fd = rc;
134 
135 	/*
136 	 * Read disklabel.
137 	 */
138 
139 	if (pmon_getdisklabel(pi) != 0) {
140 		pmon_ioclose(f);
141 		return ENXIO;
142 	}
143 
144 	if (part >= pi->label.d_npartitions) {
145 		pmon_ioclose(f);
146 		return EPART;
147 	}
148 
149 	pi->partoff = DL_GETPOFFSET(&pi->label.d_partitions[part]);
150 	pi->curpos = 0;
151 
152 	return 0;
153 }
154 
155 int
156 pmon_ioclose(struct open_file *f)
157 {
158 	struct pmon_iodata *pi;
159 	int rc;
160 
161 	if (f->f_devdata != NULL) {
162 		pi = (struct pmon_iodata *)f->f_devdata;
163 		rc = pmon_close(pi->fd);
164 		free(pi, sizeof *pi);
165 		f->f_devdata = NULL;
166 	} else
167 		rc = 0;
168 
169 	return rc;
170 }
171 
172 /*
173  * Read disk label from the device.
174  */
175 int
176 pmon_getdisklabel(struct pmon_iodata *pi)
177 {
178 	char *msg;
179 	int sector;
180 	size_t rsize;
181 	struct disklabel *lp = &pi->label;
182 	char buf[DEV_BSIZE];
183 
184 	bzero(lp, sizeof *lp);
185 
186 	/*
187 	 * Find OpenBSD Partition in DOS partition table.
188 	 */
189 	sector = 0;
190 	if (pmon_iostrategy(pi, F_READ, DOSBBSECTOR, DEV_BSIZE, buf, &rsize))
191 		return ENXIO;
192 
193 	if (*(u_int16_t *)&buf[DOSMBR_SIGNATURE_OFF] == DOSMBR_SIGNATURE) {
194 		int i;
195 		struct dos_partition *dp = (struct dos_partition *)buf;
196 
197 		/*
198 		 * Lookup OpenBSD slice. If there is none, go ahead
199 		 * and try to read the disklabel off sector #0.
200 		 */
201 		memcpy(dp, &buf[DOSPARTOFF], NDOSPART * sizeof(*dp));
202 		for (i = 0; i < NDOSPART; i++) {
203 			if (dp[i].dp_typ == DOSPTYP_OPENBSD) {
204 				sector = letoh32(dp[i].dp_start);
205 				break;
206 			}
207 		}
208 	}
209 
210 	if (pmon_iostrategy(pi, F_READ, sector + LABELSECTOR, DEV_BSIZE,
211 				buf, &rsize))
212 		return ENXIO;
213 
214 	if ((msg = getdisklabel(buf + LABELOFFSET, lp))) {
215 		printf("getdisklabel: %s\n", msg);
216 		return ENXIO;
217 	}
218 
219 	return 0;
220 }
221