1*6122d1a1Sandvar /* $NetBSD: next68k.c,v 1.10 2023/02/14 20:27:17 andvar Exp $ */
2e05d95b9Scl
3e05d95b9Scl /*-
4e05d95b9Scl * Copyright (c) 2003 The NetBSD Foundation, Inc.
5e05d95b9Scl * All rights reserved.
6e05d95b9Scl *
7e05d95b9Scl * This code is derived from software contributed to The NetBSD Foundation
8e05d95b9Scl * by David Laight and Christian Limpach.
9e05d95b9Scl *
10e05d95b9Scl * Redistribution and use in source and binary forms, with or without
11e05d95b9Scl * modification, are permitted provided that the following conditions
12e05d95b9Scl * are met:
13e05d95b9Scl * 1. Redistributions of source code must retain the above copyright
14e05d95b9Scl * notice, this list of conditions and the following disclaimer.
15e05d95b9Scl * 2. Redistributions in binary form must reproduce the above copyright
16e05d95b9Scl * notice, this list of conditions and the following disclaimer in the
17e05d95b9Scl * documentation and/or other materials provided with the distribution.
18e05d95b9Scl *
19e05d95b9Scl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20e05d95b9Scl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21e05d95b9Scl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22e05d95b9Scl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23e05d95b9Scl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24e05d95b9Scl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25e05d95b9Scl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26e05d95b9Scl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27e05d95b9Scl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28e05d95b9Scl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29e05d95b9Scl * POSSIBILITY OF SUCH DAMAGE.
30e05d95b9Scl */
31e05d95b9Scl
32e05d95b9Scl #if HAVE_NBTOOL_CONFIG_H
33e05d95b9Scl #include "nbtool_config.h"
34e05d95b9Scl #endif
35e05d95b9Scl
36f4f2cda6Slukem #include <sys/cdefs.h>
37f4f2cda6Slukem #if !defined(__lint)
38*6122d1a1Sandvar __RCSID("$NetBSD: next68k.c,v 1.10 2023/02/14 20:27:17 andvar Exp $");
39f4f2cda6Slukem #endif /* !__lint */
40f4f2cda6Slukem
41e05d95b9Scl #include <sys/param.h>
42e05d95b9Scl
43e05d95b9Scl #include <assert.h>
44e05d95b9Scl #include <err.h>
45e05d95b9Scl #include <md5.h>
46e05d95b9Scl #include <stddef.h>
47e05d95b9Scl #include <stdio.h>
48e05d95b9Scl #include <stdlib.h>
49e05d95b9Scl #include <string.h>
50e05d95b9Scl #include <unistd.h>
51e05d95b9Scl
52e05d95b9Scl #include "installboot.h"
53e05d95b9Scl
54e05d95b9Scl static uint16_t nextstep_checksum(const void *, const void *);
55cce659e2Sdsl static int next68k_setboot(ib_params *);
56cce659e2Sdsl
57e5c09b19Sthorpej struct ib_mach ib_mach_next68k = {
58e5c09b19Sthorpej .name = "next68k",
59e5c09b19Sthorpej .setboot = next68k_setboot,
60e5c09b19Sthorpej .clearboot = no_clearboot,
61e5c09b19Sthorpej .editboot = no_editboot,
62e5c09b19Sthorpej };
63e05d95b9Scl
64e05d95b9Scl static uint16_t
nextstep_checksum(const void * vbuf,const void * vlimit)65e05d95b9Scl nextstep_checksum(const void *vbuf, const void *vlimit)
66e05d95b9Scl {
67e05d95b9Scl const uint16_t *buf = vbuf;
68e05d95b9Scl const uint16_t *limit = vlimit;
69b2f78261Sjmc u_int sum = 0;
70e05d95b9Scl
71e05d95b9Scl while (buf < limit) {
72e05d95b9Scl sum += be16toh(*buf++);
73e05d95b9Scl }
74e05d95b9Scl sum += (sum >> 16);
75e05d95b9Scl return (sum & 0xffff);
76e05d95b9Scl }
77e05d95b9Scl
78cce659e2Sdsl static int
next68k_setboot(ib_params * params)79e05d95b9Scl next68k_setboot(ib_params *params)
80e05d95b9Scl {
81e05d95b9Scl int retval, labelupdated;
82e05d95b9Scl uint8_t *bootbuf;
832b2f4703Slukem size_t bootsize;
84e05d95b9Scl ssize_t rv;
85e05d95b9Scl uint32_t cd_secsize;
86e05d95b9Scl int sec_netonb_mult;
87e05d95b9Scl struct next68k_disklabel *next68klabel;
88e05d95b9Scl uint16_t *checksum;
89e05d95b9Scl uint32_t fp, b0, b1;
90e05d95b9Scl
91e05d95b9Scl assert(params != NULL);
92e05d95b9Scl assert(params->fsfd != -1);
93e05d95b9Scl assert(params->filesystem != NULL);
94e05d95b9Scl assert(params->s1fd != -1);
95e05d95b9Scl assert(params->stage1 != NULL);
96e05d95b9Scl
97e05d95b9Scl retval = 0;
98e05d95b9Scl labelupdated = 0;
99e05d95b9Scl bootbuf = NULL;
100e05d95b9Scl
101e05d95b9Scl next68klabel = malloc(NEXT68K_LABEL_SIZE);
102e05d95b9Scl if (next68klabel == NULL) {
103f4f2cda6Slukem warn("Allocating %lu bytes", (unsigned long)NEXT68K_LABEL_SIZE);
104e05d95b9Scl goto done;
105e05d95b9Scl }
106e05d95b9Scl
107e05d95b9Scl /*
108e05d95b9Scl * Read in the next68k disklabel
109e05d95b9Scl */
110e05d95b9Scl rv = pread(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE,
11117ad8eceStsutsui NEXT68K_LABEL_SECTOR * params->sectorsize + NEXT68K_LABEL_OFFSET);
112e05d95b9Scl if (rv == -1) {
113e05d95b9Scl warn("Reading `%s'", params->filesystem);
114e05d95b9Scl goto done;
115e05d95b9Scl }
116e05d95b9Scl if (rv != NEXT68K_LABEL_SIZE) {
117e05d95b9Scl warnx("Reading `%s': short read", params->filesystem);
118e05d95b9Scl goto done;
119e05d95b9Scl }
120e05d95b9Scl if (be32toh(next68klabel->cd_version) == NEXT68K_LABEL_CD_V3) {
121e05d95b9Scl checksum = &next68klabel->NEXT68K_LABEL_cd_v3_checksum;
122e05d95b9Scl } else {
123e05d95b9Scl checksum = &next68klabel->cd_checksum;
124e05d95b9Scl }
125e05d95b9Scl if (nextstep_checksum (next68klabel, checksum) !=
126e05d95b9Scl be16toh(*checksum)) {
127f4f2cda6Slukem warn("Disklabel checksum invalid on `%s'",
128e05d95b9Scl params->filesystem);
129e05d95b9Scl goto done;
130e05d95b9Scl }
131e05d95b9Scl
132e05d95b9Scl cd_secsize = be32toh(next68klabel->cd_secsize);
13317ad8eceStsutsui sec_netonb_mult = (cd_secsize / params->sectorsize);
134e05d95b9Scl
135e05d95b9Scl /*
136e05d95b9Scl * Allocate a buffer, with space to round up the input file
137e05d95b9Scl * to the next block size boundary, and with space for the boot
138e05d95b9Scl * block.
139e05d95b9Scl */
140e05d95b9Scl bootsize = roundup(params->s1stat.st_size, cd_secsize);
141e05d95b9Scl
142e05d95b9Scl bootbuf = malloc(bootsize);
143e05d95b9Scl if (bootbuf == NULL) {
1442b2f4703Slukem warn("Allocating %zu bytes", bootsize);
145e05d95b9Scl goto done;
146e05d95b9Scl }
147e05d95b9Scl memset(bootbuf, 0, bootsize);
148e05d95b9Scl
149e05d95b9Scl /*
150e05d95b9Scl * Read the file into the buffer.
151e05d95b9Scl */
152e05d95b9Scl rv = pread(params->s1fd, bootbuf, params->s1stat.st_size, 0);
153e05d95b9Scl if (rv == -1) {
154e05d95b9Scl warn("Reading `%s'", params->stage1);
155e05d95b9Scl goto done;
156e05d95b9Scl } else if (rv != params->s1stat.st_size) {
157e05d95b9Scl warnx("Reading `%s': short read", params->stage1);
158e05d95b9Scl goto done;
159e05d95b9Scl }
160e05d95b9Scl
161e05d95b9Scl if (bootsize > be16toh(next68klabel->cd_front) * cd_secsize -
162e05d95b9Scl NEXT68K_LABEL_SIZE) {
163e05d95b9Scl warnx("Boot program is larger than front porch space");
164e05d95b9Scl goto done;
165e05d95b9Scl }
166e05d95b9Scl
167e05d95b9Scl fp = be16toh(next68klabel->cd_front);
168e05d95b9Scl b0 = be32toh(next68klabel->cd_boot_blkno[0]);
169e05d95b9Scl b1 = be32toh(next68klabel->cd_boot_blkno[1]);
170e05d95b9Scl
171e05d95b9Scl if (b0 > fp)
172e05d95b9Scl b0 = fp;
173e05d95b9Scl if (b1 > fp)
174e05d95b9Scl b1 = fp;
175e05d95b9Scl if (((bootsize / cd_secsize) > b1 - b0) ||
176e05d95b9Scl ((bootsize / cd_secsize) > fp - b1)) {
177e05d95b9Scl if (2 * bootsize > (fp * cd_secsize - NEXT68K_LABEL_SIZE))
178e05d95b9Scl /* can only fit one copy */
179e05d95b9Scl b0 = b1 = NEXT68K_LABEL_SIZE / cd_secsize;
180e05d95b9Scl else {
181e05d95b9Scl if (2 * bootsize > (fp * cd_secsize -
18217ad8eceStsutsui NEXT68K_LABEL_DEFAULTBOOT0_1 *
18317ad8eceStsutsui params->sectorsize))
184e05d95b9Scl /* can fit two copies starting after label */
185e05d95b9Scl b0 = NEXT68K_LABEL_SIZE / cd_secsize;
186e05d95b9Scl else
187e05d95b9Scl /* can fit two copies starting at default 1 */
188e05d95b9Scl b0 = NEXT68K_LABEL_DEFAULTBOOT0_1 /
189e05d95b9Scl sec_netonb_mult;
190e05d95b9Scl /* try to fit 2nd copy at default 2 */
191e05d95b9Scl b1 = NEXT68K_LABEL_DEFAULTBOOT0_2 / sec_netonb_mult;
192e05d95b9Scl if (fp < b1)
193e05d95b9Scl b1 = fp;
194e05d95b9Scl if (bootsize / cd_secsize > (fp - b1))
195e05d95b9Scl /* fit 2nd copy before front porch */
196e05d95b9Scl b1 = fp - bootsize / cd_secsize;
197e05d95b9Scl }
198e05d95b9Scl }
1992b2f4703Slukem if (next68klabel->cd_boot_blkno[0] != (int32_t)htobe32(b0)) {
200e05d95b9Scl next68klabel->cd_boot_blkno[0] = htobe32(b0);
201e05d95b9Scl labelupdated = 1;
202e05d95b9Scl }
2032b2f4703Slukem if (next68klabel->cd_boot_blkno[1] != (int32_t)htobe32(b1)) {
204e05d95b9Scl next68klabel->cd_boot_blkno[1] = htobe32(b1);
205e05d95b9Scl labelupdated = 1;
206e05d95b9Scl }
207e05d95b9Scl if (params->flags & IB_VERBOSE)
208*6122d1a1Sandvar printf("Boot program locations%s: %d %d\n",
209e05d95b9Scl labelupdated ? " updated" : "", b0 * sec_netonb_mult,
210e05d95b9Scl b1 * sec_netonb_mult);
211e05d95b9Scl
212e05d95b9Scl if (params->flags & IB_NOWRITE) {
213e05d95b9Scl retval = 1;
214e05d95b9Scl goto done;
215e05d95b9Scl }
216e05d95b9Scl
217e05d95b9Scl /*
218e05d95b9Scl * Write the updated next68k disklabel
219e05d95b9Scl */
220e05d95b9Scl if (labelupdated) {
221e05d95b9Scl if (params->flags & IB_VERBOSE)
222e05d95b9Scl printf ("Writing updated label\n");
223e05d95b9Scl *checksum = htobe16(nextstep_checksum (next68klabel,
224e05d95b9Scl checksum));
225e05d95b9Scl rv = pwrite(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE,
22617ad8eceStsutsui NEXT68K_LABEL_SECTOR * params->sectorsize +
22717ad8eceStsutsui NEXT68K_LABEL_OFFSET);
228e05d95b9Scl if (rv == -1) {
229e05d95b9Scl warn("Writing `%s'", params->filesystem);
230e05d95b9Scl goto done;
231e05d95b9Scl }
232e05d95b9Scl if (rv != NEXT68K_LABEL_SIZE) {
233e05d95b9Scl warnx("Writing `%s': short write", params->filesystem);
234e05d95b9Scl goto done;
235e05d95b9Scl }
236e05d95b9Scl }
237e05d95b9Scl
238e05d95b9Scl b0 *= sec_netonb_mult;
239e05d95b9Scl b1 *= sec_netonb_mult;
240e05d95b9Scl
241e05d95b9Scl /*
242e05d95b9Scl * Write boot program to locations b0 and b1 (if different).
243e05d95b9Scl */
244e05d95b9Scl for (;;) {
245e05d95b9Scl if (params->flags & IB_VERBOSE)
246e05d95b9Scl printf ("Writing boot program at %d\n", b0);
24717ad8eceStsutsui rv = pwrite(params->fsfd, bootbuf, bootsize,
24817ad8eceStsutsui b0 * params->sectorsize);
249e05d95b9Scl if (rv == -1) {
250e05d95b9Scl warn("Writing `%s' at %d", params->filesystem, b0);
251e05d95b9Scl goto done;
252e05d95b9Scl }
2532b2f4703Slukem if ((size_t)rv != bootsize) {
254e05d95b9Scl warnx("Writing `%s' at %d: short write",
255e05d95b9Scl params->filesystem, b0);
256e05d95b9Scl goto done;
257e05d95b9Scl }
258e05d95b9Scl if (b0 == b1)
259e05d95b9Scl break;
260e05d95b9Scl b0 = b1;
261e05d95b9Scl }
262e05d95b9Scl
263e05d95b9Scl retval = 1;
264e05d95b9Scl
265e05d95b9Scl done:
266e05d95b9Scl if (bootbuf)
267e05d95b9Scl free(bootbuf);
268e05d95b9Scl if (next68klabel)
269e05d95b9Scl free(next68klabel);
270e05d95b9Scl return retval;
271e05d95b9Scl }
272