xref: /netbsd-src/usr.sbin/installboot/arch/sparc.c (revision 04e61f8526dc919e1c004e02c39dea35e7c0f042)
1 /*	$NetBSD: sparc.c,v 1.1 2002/05/06 16:24:46 pk Exp $ */
2 
3 /*-
4  * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Fredette, Paul Kranenburg, and Luke Mewburn.
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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 #if defined(__RCSID) && !defined(__lint)
41 __RCSID("$NetBSD: sparc.c,v 1.1 2002/05/06 16:24:46 pk Exp $");
42 #endif	/* !__lint */
43 
44 #if HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47 
48 #include <sys/param.h>
49 #include <sys/stat.h>
50 
51 #include <assert.h>
52 #include <err.h>
53 #include <stddef.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 
59 #if HAVE_CONFIG_H
60 #include "../../sys/sys/bootblock.h"
61 #else
62 #include <sys/bootblock.h>
63 #endif
64 
65 #include "installboot.h"
66 
67 int
68 sparc_clearboot(ib_params *params)
69 {
70 	char	bb[SPARC_BOOT_BLOCK_MAX_SIZE];
71 	ssize_t	rv;
72 
73 	assert(params != NULL);
74 	assert(params->fsfd != -1);
75 	assert(params->filesystem != NULL);
76 
77 	if (params->flags & IB_STARTBLOCK) {
78 		warnx("Can't use `-b bno' with `-c'");
79 		return (0);
80 	}
81 
82 	/* first check that it _could_ exist here */
83 	rv = pread(params->fsfd, &bb, sizeof(bb), SPARC_BOOT_BLOCK_OFFSET);
84 	if (rv == -1) {
85 		warn("Reading `%s'", params->filesystem);
86 		return (0);
87 	} else if (rv != sizeof(bb)) {
88 		warnx("Reading `%s': short read", params->filesystem);
89 		return (0);
90 	}
91 
92 	/* now clear it out to nothing */
93 	memset(&bb, 0, sizeof(bb));
94 
95 	if (params->flags & IB_VERBOSE)
96 		printf("%slearing boot block\n",
97 		    (params->flags & IB_NOWRITE) ? "Not c" : "C");
98 	if (params->flags & IB_NOWRITE)
99 		return (1);
100 
101 	rv = pwrite(params->fsfd, &bb, sizeof(bb), SPARC_BOOT_BLOCK_OFFSET);
102 	if (rv == -1) {
103 		warn("Writing `%s'", params->filesystem);
104 		return (0);
105 	} else if (rv != sizeof(bb)) {
106 		warnx("Writing `%s': short write", params->filesystem);
107 		return (0);
108 	}
109 
110 	return (1);
111 }
112 
113 int
114 sparc_setboot(ib_params *params)
115 {
116 	struct stat	bootstrapsb;
117 	char		bb[SPARC_BOOT_BLOCK_MAX_SIZE];
118 	uint32_t	startblock;
119 	int		retval;
120 	ssize_t		rv;
121 	size_t		bbi;
122 	struct sparc_bbinfo	*bbinfop;	/* bbinfo in prototype image */
123 	uint32_t	maxblk, nblk, blk_i;
124 	ib_block	*blocks = NULL;
125 
126 	assert(params != NULL);
127 	assert(params->fsfd != -1);
128 	assert(params->filesystem != NULL);
129 	assert(params->fstype != NULL);
130 	assert(params->s1fd != -1);
131 	assert(params->stage1 != NULL);
132 	assert(SPARC_BBINFO_MAGICSIZE == 32);
133 
134 	if (params->stage2 == NULL) {
135 		warnx("You must provide the name of the secondary bootstrap");
136 		return (0);
137 	}
138 
139 	retval = 0;
140 
141 	if (fstat(params->s1fd, &bootstrapsb) == -1) {
142 		warn("Examining `%s'", params->stage1);
143 		goto done;
144 	}
145 	if (!S_ISREG(bootstrapsb.st_mode)) {
146 		warnx("`%s' must be a regular file", params->stage1);
147 		goto done;
148 	}
149 	if (bootstrapsb.st_size > sizeof(bb)) {
150 		warnx("`%s' cannot be larger than %lu bytes",
151 		    params->stage1, (unsigned long)sizeof(bb));
152 		goto done;
153 	}
154 
155 	/*
156 	 * Read 1st stage boot program
157 	 * Leave room for a 32-byte a.out header.
158 	 */
159 	memset(&bb, 0, sizeof(bb));
160 	rv = read(params->s1fd, bb + 32, sizeof(bb) - 32);
161 	if (rv == -1) {
162 		warn("Reading `%s'", params->stage1);
163 		goto done;
164 	}
165 
166 	/*
167 	 * Quick sanity check that the bootstrap given
168 	 * is *not* an ELF executable.
169 	 */
170 	if (memcmp(bb + 32 + 1, "ELF", strlen("ELF")) == 0) {
171 		warnx("`%s' is an ELF executable; need raw binary",
172 		    params->stage1);
173 		goto done;
174 	}
175 
176 	/* Look for the bbinfo structure. */
177 	for (bbi = 0; bbi < sizeof(bb); bbi += sizeof(uint32_t)) {
178 		bbinfop = (void *) (bb + bbi);
179 		if (memcmp(bbinfop->bbi_magic, SPARC_BBINFO_MAGIC,
180 			    SPARC_BBINFO_MAGICSIZE) == 0)
181 			break;
182 	}
183 	if (bbi >= sizeof(bb)) {
184 		warnx("`%s' does not have a bbinfo structure\n",
185 		    params->stage1);
186 		goto done;
187 	}
188 	maxblk = be32toh(bbinfop->bbi_block_count);
189 	if (maxblk == 0 || maxblk > (sizeof(bb) / sizeof(uint32_t))) {
190 		warnx("bbinfo structure in `%s' has preposterous size `%u'",
191 		    params->stage1, maxblk);
192 		goto done;
193 	}
194 
195 	/* Allocate space for our block list. */
196 	blocks = malloc(sizeof(*blocks) * maxblk);
197 	if (blocks == NULL) {
198 		warn("Allocating %lu bytes",
199 		    (unsigned long) sizeof(*blocks) * maxblk);
200 		goto done;
201 	}
202 
203 	/* Make sure the (probably new) secondary bootstrap is on disk. */
204 	sync(); sleep(1); sync();
205 
206 	/* Collect the blocks for the secondary bootstrap. */
207 	nblk = maxblk;
208 	if (! params->fstype->findstage2(params, &nblk, blocks))
209 		goto done;
210 	if (nblk == 0) {
211 		warnx("Secondary bootstrap `%s' is empty",
212 		   params->stage2);
213 		goto done;
214 	}
215 
216 	/* Save those blocks in the primary bootstrap. */
217 	bbinfop->bbi_block_count = htobe32(nblk);
218 	bbinfop->bbi_block_size = htobe32(blocks[0].blocksize);
219 	for (blk_i = 0; blk_i < nblk; blk_i++) {
220 		bbinfop->bbi_block_table[blk_i] =
221 		    htobe32(blocks[blk_i].block);
222 		if (blocks[blk_i].blocksize < blocks[0].blocksize &&
223 		    blk_i + 1 != nblk) {
224 			warnx("Secondary bootstrap `%s' blocks do not have " \
225 			    "a uniform size\n", params->stage2);
226 			goto done;
227 		}
228 	}
229 
230 	/*
231 	 * sun4c/sun4m PROMs require an a.out(5) format header.
232 	 * Old-style sun4 PROMs do not expect a header at all.
233 	 * To deal with this, we construct a header that is also executable
234 	 * code containing a forward branch that gets us past the 32-byte
235 	 * header where the actual code begins. In assembly:
236 	 * 	.word	MAGIC		! a NOP
237 	 * 	ba,a	start		!
238 	 * 	.skip	24		! pad
239 	 * start:
240 	 */
241 #define SUN_MAGIC	0x01030107
242 #define SUN4_BASTART	0x30800007	/* i.e.: ba,a `start' */
243 	*((uint32_t *)bb) = htobe32(SUN_MAGIC);
244 	*((uint32_t *)bb + 1) = htobe32(SUN4_BASTART);
245 
246 	if (params->flags & IB_STARTBLOCK)
247 		startblock = params->startblock;
248 	else
249 		startblock =
250 			SPARC_BOOT_BLOCK_OFFSET / SPARC_BOOT_BLOCK_BLOCKSIZE;
251 
252 	if (params->flags & IB_VERBOSE) {
253 		printf("Bootstrap start sector: %u\n", startblock);
254 		printf("Bootstrap byte count:   %u\n", (unsigned)rv);
255 		printf("Bootstrap block table:  %u entries avail, %u used:",
256 		    maxblk, nblk);
257 		for (blk_i = 0; blk_i < nblk; blk_i++)
258 			printf(" %u", blocks[blk_i].block);
259 		printf("\n%sriting bootstrap\n",
260 		    (params->flags & IB_NOWRITE) ? "Not w" : "W");
261 	}
262 	if (params->flags & IB_NOWRITE) {
263 		retval = 1;
264 		goto done;
265 	}
266 
267 	rv = pwrite(params->fsfd, &bb, sizeof(bb),
268 		    startblock * SPARC_BOOT_BLOCK_BLOCKSIZE);
269 	if (rv == -1) {
270 		warn("Writing `%s'", params->filesystem);
271 		goto done;
272 	} else if (rv != sizeof(bb)) {
273 		warnx("Writing `%s': short write", params->filesystem);
274 		goto done;
275 	} else {
276 
277 		/* Sync filesystems (to clean in-memory superblock?) */
278 		sync();
279 
280 		retval = 1;
281 	}
282 
283  done:
284 	if (blocks != NULL)
285 		free (blocks);
286 	return (retval);
287 }
288