xref: /netbsd-src/usr.sbin/installboot/arch/vax.c (revision 492c086f0af68dad916940c3174e962380fdd377)
1*492c086fSandvar /*	$NetBSD: vax.c,v 1.20 2022/01/24 09:14:38 andvar Exp $	*/
2c37fa0ceSlukem 
3c37fa0ceSlukem /*-
4c37fa0ceSlukem  * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
5c37fa0ceSlukem  * All rights reserved.
6c37fa0ceSlukem  *
7c37fa0ceSlukem  * This code is derived from software contributed to The NetBSD Foundation
8c37fa0ceSlukem  * by Simon Burge.
9c37fa0ceSlukem  *
10c37fa0ceSlukem  * This code is derived from software contributed to The NetBSD Foundation
11c37fa0ceSlukem  * by Luke Mewburn of Wasabi Systems.
12c37fa0ceSlukem  *
13c37fa0ceSlukem  * Redistribution and use in source and binary forms, with or without
14c37fa0ceSlukem  * modification, are permitted provided that the following conditions
15c37fa0ceSlukem  * are met:
16c37fa0ceSlukem  * 1. Redistributions of source code must retain the above copyright
17c37fa0ceSlukem  *    notice, this list of conditions and the following disclaimer.
18c37fa0ceSlukem  * 2. Redistributions in binary form must reproduce the above copyright
19c37fa0ceSlukem  *    notice, this list of conditions and the following disclaimer in the
20c37fa0ceSlukem  *    documentation and/or other materials provided with the distribution.
21c37fa0ceSlukem  *
22c37fa0ceSlukem  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23c37fa0ceSlukem  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24c37fa0ceSlukem  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25c37fa0ceSlukem  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26c37fa0ceSlukem  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27c37fa0ceSlukem  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28c37fa0ceSlukem  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29c37fa0ceSlukem  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30c37fa0ceSlukem  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31c37fa0ceSlukem  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32c37fa0ceSlukem  * POSSIBILITY OF SUCH DAMAGE.
33c37fa0ceSlukem  */
34c37fa0ceSlukem 
35c37fa0ceSlukem /*
36c37fa0ceSlukem  * Copyright (c) 1999 Christopher G. Demetriou.  All rights reserved.
37c37fa0ceSlukem  *
38c37fa0ceSlukem  * Redistribution and use in source and binary forms, with or without
39c37fa0ceSlukem  * modification, are permitted provided that the following conditions
40c37fa0ceSlukem  * are met:
41c37fa0ceSlukem  * 1. Redistributions of source code must retain the above copyright
42c37fa0ceSlukem  *    notice, this list of conditions and the following disclaimer.
43c37fa0ceSlukem  * 2. Redistributions in binary form must reproduce the above copyright
44c37fa0ceSlukem  *    notice, this list of conditions and the following disclaimer in the
45c37fa0ceSlukem  *    documentation and/or other materials provided with the distribution.
46c37fa0ceSlukem  * 3. All advertising materials mentioning features or use of this software
47c37fa0ceSlukem  *    must display the following acknowledgement:
48c37fa0ceSlukem  *      This product includes software developed by Christopher G. Demetriou
49c37fa0ceSlukem  *	for the NetBSD Project.
50c37fa0ceSlukem  * 4. The name of the author may not be used to endorse or promote products
51c37fa0ceSlukem  *    derived from this software without specific prior written permission
52c37fa0ceSlukem  *
53c37fa0ceSlukem  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
54c37fa0ceSlukem  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
55c37fa0ceSlukem  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
56c37fa0ceSlukem  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
57c37fa0ceSlukem  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
58c37fa0ceSlukem  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59c37fa0ceSlukem  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60c37fa0ceSlukem  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61c37fa0ceSlukem  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
62c37fa0ceSlukem  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63c37fa0ceSlukem  */
64c37fa0ceSlukem 
65171d6532Slukem #if HAVE_NBTOOL_CONFIG_H
66171d6532Slukem #include "nbtool_config.h"
674887cf34Stv #endif
684887cf34Stv 
69171d6532Slukem #include <sys/cdefs.h>
70171d6532Slukem #if !defined(__lint)
71*492c086fSandvar __RCSID("$NetBSD: vax.c,v 1.20 2022/01/24 09:14:38 andvar Exp $");
72171d6532Slukem #endif	/* !__lint */
73171d6532Slukem 
74c37fa0ceSlukem #include <sys/param.h>
75252b8260Smatt #ifdef HAVE_NBTOOL_CONFIG_H
76252b8260Smatt #include <nbinclude/vax/disklabel.h>
77252b8260Smatt #else
78e23a017dSmartin #include <sys/disklabel.h>
79252b8260Smatt #endif
80c37fa0ceSlukem 
81c37fa0ceSlukem #include <assert.h>
82c37fa0ceSlukem #include <err.h>
83c37fa0ceSlukem #include <stddef.h>
84c37fa0ceSlukem #include <stdio.h>
85c37fa0ceSlukem #include <stdlib.h>
86e23a017dSmartin #include <string.h>
87c37fa0ceSlukem #include <unistd.h>
88c37fa0ceSlukem 
89c37fa0ceSlukem #include "installboot.h"
90c37fa0ceSlukem 
91039e2096Schristos #define	VAX_LABELOFFSET		64
92039e2096Schristos 
9367c2857bSmartin #ifndef __CTASSERT
9467c2857bSmartin #define	__CTASSERT(X)
9567c2857bSmartin #endif
9667c2857bSmartin 
97c37fa0ceSlukem static int	load_bootstrap(ib_params *, char **,
988eb8919eSlukem 		    uint32_t *, uint32_t *, size_t *);
99c37fa0ceSlukem 
100cce659e2Sdsl static int vax_clearboot(ib_params *);
101cce659e2Sdsl static int vax_setboot(ib_params *);
102cce659e2Sdsl 
103e5c09b19Sthorpej struct ib_mach ib_mach_vax = {
104e5c09b19Sthorpej 	.name		=	"vax",
105e5c09b19Sthorpej 	.setboot	=	vax_setboot,
106e5c09b19Sthorpej 	.clearboot	=	vax_clearboot,
107e5c09b19Sthorpej 	.editboot	=	no_editboot,
108e5c09b19Sthorpej 	.valid_flags	=	IB_STAGE1START | IB_APPEND | IB_SUNSUM,
109e5c09b19Sthorpej };
110cce659e2Sdsl 
111cce659e2Sdsl static int
vax_clearboot(ib_params * params)112c37fa0ceSlukem vax_clearboot(ib_params *params)
113c37fa0ceSlukem {
114c37fa0ceSlukem 	struct vax_boot_block	bb;
115c37fa0ceSlukem 	ssize_t			rv;
116c37fa0ceSlukem 
117c37fa0ceSlukem 	assert(params != NULL);
118c37fa0ceSlukem 	assert(params->fsfd != -1);
119c37fa0ceSlukem 	assert(params->filesystem != NULL);
120e23a017dSmartin 	__CTASSERT(sizeof(bb)==VAX_BOOT_BLOCK_BLOCKSIZE);
121c37fa0ceSlukem 
122c37fa0ceSlukem 	rv = pread(params->fsfd, &bb, sizeof(bb), VAX_BOOT_BLOCK_OFFSET);
123c37fa0ceSlukem 	if (rv == -1) {
124c37fa0ceSlukem 		warn("Reading `%s'", params->filesystem);
125c37fa0ceSlukem 		return (0);
126c37fa0ceSlukem 	} else if (rv != sizeof(bb)) {
127c37fa0ceSlukem 		warnx("Reading `%s': short read", params->filesystem);
128c37fa0ceSlukem 		return (0);
129c37fa0ceSlukem 	}
130c37fa0ceSlukem 
131e23a017dSmartin 	if (bb.bb_id_offset*2 >= VAX_BOOT_BLOCK_BLOCKSIZE
132c37fa0ceSlukem 	    || bb.bb_magic1 != VAX_BOOT_MAGIC1) {
133c37fa0ceSlukem 		warnx(
134c37fa0ceSlukem 		    "Old boot block magic number invalid; boot block invalid");
135c37fa0ceSlukem 		return (0);
136c37fa0ceSlukem 	}
137c37fa0ceSlukem 
138c37fa0ceSlukem 	bb.bb_id_offset = 1;
139c37fa0ceSlukem 	bb.bb_mbone = 0;
140c37fa0ceSlukem 	bb.bb_lbn_hi = 0;
141c37fa0ceSlukem 	bb.bb_lbn_low = 0;
142c37fa0ceSlukem 
143c37fa0ceSlukem 	if (params->flags & IB_SUNSUM) {
1448eb8919eSlukem 		uint16_t	sum;
145c37fa0ceSlukem 
1468eb8919eSlukem 		sum = compute_sunsum((uint16_t *)&bb);
1478eb8919eSlukem 		if (! set_sunsum(params, (uint16_t *)&bb, sum))
148c37fa0ceSlukem 			return (0);
149c37fa0ceSlukem 	}
150c37fa0ceSlukem 
151c37fa0ceSlukem 	if (params->flags & IB_VERBOSE)
152c37fa0ceSlukem 		printf("%slearing boot block\n",
153c37fa0ceSlukem 		    (params->flags & IB_NOWRITE) ? "Not c" : "C");
154c37fa0ceSlukem 	if (params->flags & IB_NOWRITE)
155c37fa0ceSlukem 		return (1);
156c37fa0ceSlukem 
157c37fa0ceSlukem 	rv = pwrite(params->fsfd, &bb, sizeof(bb), VAX_BOOT_BLOCK_OFFSET);
158c37fa0ceSlukem 	if (rv == -1) {
159c37fa0ceSlukem 		warn("Writing `%s'", params->filesystem);
160c37fa0ceSlukem 		return (0);
161c37fa0ceSlukem 	} else if (rv != sizeof(bb)) {
162c37fa0ceSlukem 		warnx("Writing `%s': short write", params->filesystem);
163c37fa0ceSlukem 		return (0);
164c37fa0ceSlukem 	}
165c37fa0ceSlukem 
166c37fa0ceSlukem 	return (1);
167c37fa0ceSlukem }
168c37fa0ceSlukem 
169cce659e2Sdsl static int
vax_setboot(ib_params * params)170c37fa0ceSlukem vax_setboot(ib_params *params)
171c37fa0ceSlukem {
172c37fa0ceSlukem 	struct stat		bootstrapsb;
173e23a017dSmartin 	struct vax_boot_block	*bb;
1748eb8919eSlukem 	uint32_t		startblock;
1758eb8919eSlukem 	int			retval;
176e23a017dSmartin 	char			*bootstrapbuf, oldbb[VAX_BOOT_BLOCK_BLOCKSIZE];
177c37fa0ceSlukem 	size_t			bootstrapsize;
1788eb8919eSlukem 	uint32_t		bootstrapload, bootstrapexec;
179c37fa0ceSlukem 	ssize_t			rv;
180c37fa0ceSlukem 
181c37fa0ceSlukem 	assert(params != NULL);
182c37fa0ceSlukem 	assert(params->fsfd != -1);
183c37fa0ceSlukem 	assert(params->filesystem != NULL);
184d2804426Slukem 	assert(params->s1fd != -1);
185d2804426Slukem 	assert(params->stage1 != NULL);
186c37fa0ceSlukem 
187e23a017dSmartin 	/* see sys/arch/vax/boot/xxboot/start.S for explanation */
188e23a017dSmartin 	__CTASSERT(offsetof(struct vax_boot_block,bb_magic1) == 0x19e);
189e23a017dSmartin 	__CTASSERT(sizeof(struct vax_boot_block) == VAX_BOOT_BLOCK_BLOCKSIZE);
190e23a017dSmartin 
191e23a017dSmartin 	startblock = 0;
192c37fa0ceSlukem 	retval = 0;
193c37fa0ceSlukem 	bootstrapbuf = NULL;
194c37fa0ceSlukem 
195d2804426Slukem 	if (fstat(params->s1fd, &bootstrapsb) == -1) {
196d2804426Slukem 		warn("Examining `%s'", params->stage1);
197c37fa0ceSlukem 		goto done;
198c37fa0ceSlukem 	}
199c37fa0ceSlukem 	if (!S_ISREG(bootstrapsb.st_mode)) {
200d2804426Slukem 		warnx("`%s' must be a regular file", params->stage1);
201c37fa0ceSlukem 		goto done;
202c37fa0ceSlukem 	}
203c37fa0ceSlukem 	if (! load_bootstrap(params, &bootstrapbuf, &bootstrapload,
204c37fa0ceSlukem 	    &bootstrapexec, &bootstrapsize))
205c37fa0ceSlukem 		goto done;
206c37fa0ceSlukem 
207e23a017dSmartin 	/* read old boot block */
208e23a017dSmartin 	rv = pread(params->fsfd, oldbb, sizeof(oldbb), VAX_BOOT_BLOCK_OFFSET);
209c37fa0ceSlukem 	if (rv == -1) {
210c37fa0ceSlukem 		warn("Reading `%s'", params->filesystem);
211c37fa0ceSlukem 		goto done;
212e23a017dSmartin 	} else if (rv != sizeof(oldbb)) {
213c37fa0ceSlukem 		warnx("Reading `%s': short read", params->filesystem);
214c37fa0ceSlukem 		goto done;
215c37fa0ceSlukem 	}
216c37fa0ceSlukem 
217e23a017dSmartin 	/*
218e23a017dSmartin 	 * Copy disklabel from old boot block to new.
219039e2096Schristos 	 * Assume everything between VAX_LABELOFFSET and the start of
220e23a017dSmartin 	 * the param block is scratch area and can be copied over.
221e23a017dSmartin 	 */
222039e2096Schristos 	memcpy(bootstrapbuf + VAX_LABELOFFSET,
223039e2096Schristos 	    oldbb + VAX_LABELOFFSET,
224039e2096Schristos 	    offsetof(struct vax_boot_block,bb_magic1) - VAX_LABELOFFSET);
225e23a017dSmartin 
226*492c086fSandvar 	/* point to bootblock at beginning of bootstrap */
227e23a017dSmartin 	bb = (struct vax_boot_block*)bootstrapbuf;
228e23a017dSmartin 
229c37fa0ceSlukem 	/* fill in the updated boot block fields */
230c37fa0ceSlukem 	if (params->flags & IB_APPEND) {
231c37fa0ceSlukem 		struct stat	filesyssb;
232c37fa0ceSlukem 
233c37fa0ceSlukem 		if (fstat(params->fsfd, &filesyssb) == -1) {
234c37fa0ceSlukem 			warn("Examining `%s'", params->filesystem);
235c37fa0ceSlukem 			goto done;
236c37fa0ceSlukem 		}
237c37fa0ceSlukem 		if (!S_ISREG(filesyssb.st_mode)) {
238c37fa0ceSlukem 			warnx(
239d2804426Slukem 		    "`%s' must be a regular file to append a bootstrap",
240c37fa0ceSlukem 			    params->filesystem);
241c37fa0ceSlukem 			goto done;
242c37fa0ceSlukem 		}
243c37fa0ceSlukem 		startblock = howmany(filesyssb.st_size,
244c37fa0ceSlukem 		    VAX_BOOT_BLOCK_BLOCKSIZE);
245e23a017dSmartin 		bb->bb_lbn_hi = htole16((uint16_t) (startblock >> 16));
246e23a017dSmartin 		bb->bb_lbn_low = htole16((uint16_t) (startblock >>  0));
247c37fa0ceSlukem 	}
248c37fa0ceSlukem 
249c37fa0ceSlukem 	if (params->flags & IB_SUNSUM) {
2508eb8919eSlukem 		uint16_t	sum;
251c37fa0ceSlukem 
252e23a017dSmartin 		sum = compute_sunsum((uint16_t *)bb);
253e23a017dSmartin 		if (! set_sunsum(params, (uint16_t *)bb, sum))
254c37fa0ceSlukem 			goto done;
255c37fa0ceSlukem 	}
256c37fa0ceSlukem 
257c37fa0ceSlukem 	if (params->flags & IB_VERBOSE) {
258d9e55fcaSlukem 		printf("Bootstrap start sector: %u\n", startblock);
259e23a017dSmartin 		printf("Bootstrap sector count: %u\n", le32toh(bb->bb_size));
260c37fa0ceSlukem 		printf("%sriting bootstrap\n",
261c37fa0ceSlukem 		    (params->flags & IB_NOWRITE) ? "Not w" : "W");
262c37fa0ceSlukem 	}
263c37fa0ceSlukem 	if (params->flags & IB_NOWRITE) {
264c37fa0ceSlukem 		retval = 1;
265c37fa0ceSlukem 		goto done;
266c37fa0ceSlukem 	}
267e23a017dSmartin 	rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize, 0);
268c37fa0ceSlukem 	if (rv == -1) {
269c37fa0ceSlukem 		warn("Writing `%s'", params->filesystem);
270c37fa0ceSlukem 		goto done;
2712b2f4703Slukem 	} else if ((size_t)rv != bootstrapsize) {
272c37fa0ceSlukem 		warnx("Writing `%s': short write", params->filesystem);
273c37fa0ceSlukem 		goto done;
274c37fa0ceSlukem 	}
275c37fa0ceSlukem 	retval = 1;
276c37fa0ceSlukem 
277c37fa0ceSlukem  done:
278c37fa0ceSlukem 	if (bootstrapbuf)
279c37fa0ceSlukem 		free(bootstrapbuf);
280c37fa0ceSlukem 	return (retval);
281c37fa0ceSlukem }
282c37fa0ceSlukem 
283c37fa0ceSlukem static int
load_bootstrap(ib_params * params,char ** data,uint32_t * loadaddr,uint32_t * execaddr,size_t * len)284c37fa0ceSlukem load_bootstrap(ib_params *params, char **data,
2858eb8919eSlukem 	uint32_t *loadaddr, uint32_t *execaddr, size_t *len)
286c37fa0ceSlukem {
287c37fa0ceSlukem 	ssize_t	cc;
288c37fa0ceSlukem 	size_t	buflen;
289c37fa0ceSlukem 
290c37fa0ceSlukem 	buflen = 512 * (VAX_BOOT_SIZE + 1);
291c37fa0ceSlukem 	*data = malloc(buflen);
292c37fa0ceSlukem 	if (*data == NULL) {
293c37fa0ceSlukem 		warn("Allocating %lu bytes", (unsigned long) buflen);
294c37fa0ceSlukem 		return (0);
295c37fa0ceSlukem 	}
296c37fa0ceSlukem 
297d2804426Slukem 	cc = pread(params->s1fd, *data, buflen, 0);
298c37fa0ceSlukem 	if (cc <= 0) {
299d2804426Slukem 		warn("Reading `%s'", params->stage1);
300c37fa0ceSlukem 		return (0);
301c37fa0ceSlukem 	}
302c37fa0ceSlukem 	if (cc > 512 * VAX_BOOT_SIZE) {
303d2804426Slukem 		warnx("`%s': too large", params->stage1);
304c37fa0ceSlukem 		return (0);
305c37fa0ceSlukem 	}
306c37fa0ceSlukem 
307c37fa0ceSlukem 	*len = roundup(cc, VAX_BOOT_BLOCK_BLOCKSIZE);
308c37fa0ceSlukem 	*loadaddr = VAX_BOOT_LOAD;
309c37fa0ceSlukem 	*execaddr = VAX_BOOT_ENTRY;
310c37fa0ceSlukem 	return (1);
311c37fa0ceSlukem }
312