1/*	$NetBSD: md.c,v 1.16 2022/06/11 16:25:23 tsutsui Exp $ */
2
3/*
4 * Copyright 1997 Piermont Information Systems Inc.
5 * All rights reserved.
6 *
7 * Based on code written by Philip A. Nelson for Piermont Information
8 * Systems Inc.
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. The name of Piermont Information Systems Inc. may not be used to endorse
19 *    or promote products derived from this software without specific prior
20 *    written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35/* md.c -- cobalt machine specific routines */
36
37#include <sys/param.h>
38#include <sys/sysctl.h>
39#include <stdio.h>
40#include <util.h>
41#include <machine/cpu.h>
42
43#include "defs.h"
44#include "md.h"
45#include "msg_defs.h"
46#include "menu_defs.h"
47
48/*
49 * Firmware reognizes only Linux Ext2 REV 0, so we have to have
50 * a Linux Ext2 fs to store our native bootloader.
51 */
52static int nobootfs = 0;
53
54void
55md_init(void)
56{
57}
58
59void
60md_init_set_status(int flags)
61{
62	(void)flags;
63}
64
65bool
66md_get_info(struct install_partition_desc *install)
67{
68	int res;
69
70	if (pm->no_mbr || pm->no_part)
71		return true;
72
73again:
74	if (pm->parts == NULL) {
75
76		const struct disk_partitioning_scheme *ps =
77		    select_part_scheme(pm, NULL, true, NULL);
78
79		if (!ps)
80			return false;
81
82		struct disk_partitions *parts =
83		   (*ps->create_new_for_disk)(pm->diskdev,
84		   0, pm->dlsize, true, NULL);
85		if (!parts)
86			return false;
87
88		pm->parts = parts;
89		if (ps->size_limit > 0 && pm->dlsize > ps->size_limit)
90			pm->dlsize = ps->size_limit;
91	}
92
93	res = set_bios_geom_with_mbr_guess(pm->parts);
94	if (res == 0)
95		return false;
96	else if (res == 1)
97		return true;
98
99	pm->parts->pscheme->destroy_part_scheme(pm->parts);
100	pm->parts = NULL;
101	goto again;
102}
103
104/*
105 * md back-end code for menu-driven BSD disklabel editor.
106 */
107int
108md_make_bsd_partitions(struct install_partition_desc *install)
109{
110	return make_bsd_partitions(install);
111}
112
113/*
114 * any additional partition validation
115 */
116bool
117md_check_partitions(struct install_partition_desc *install)
118{
119	size_t part;
120
121	/* we need to find a boot partition, otherwise we can't write our
122	 * bootloader.  We make the assumption that the user hasn't done
123	 * something stupid, like move it away from the MBR partition.
124	 */
125	for (part = 0; part < install->num; part++) {
126		if (install->infos[part].fs_type == PART_BOOT_TYPE)
127			return true;
128	}
129
130	msg_display(MSG_nobootpartdisklabel);
131	process_menu(MENU_ok, NULL);
132	return false;
133}
134
135/*
136 * hook called before writing new disklabel.
137 */
138bool
139md_pre_disklabel(struct install_partition_desc *install,
140    struct disk_partitions *parts)
141{
142
143	if (parts->parent == NULL)
144		return true;	/* no outer partitions */
145
146	parts = parts->parent;
147
148	msg_display_subst(MSG_dofdisk, 3, parts->disk,
149	    msg_string(parts->pscheme->name),
150	    msg_string(parts->pscheme->short_name));
151
152	/* write edited "MBR" onto disk. */
153	if (!parts->pscheme->write_to_disk(parts)) {
154		msg_display(MSG_wmbrfail);
155		process_menu(MENU_ok, NULL);
156		return false;
157	}
158	return true;
159}
160
161/*
162 * hook called after writing disklabel to new target disk.
163 */
164bool
165md_post_disklabel(struct install_partition_desc *install,
166    struct disk_partitions *parts)
167{
168	return true;
169}
170
171/*
172 * hook called after upgrade() or install() has finished setting
173 * up the target disk but immediately before the user is given the
174 * ``disks are now set up'' message.
175 */
176int
177md_post_newfs(struct install_partition_desc *install)
178{
179	static const char *kernels[] = {
180		"vmlinux-nfsroot.gz",
181		"vmlinux.gz",
182		"vmlinux_RAQ.gz",
183		"vmlinux_raq-2800.gz"
184	};
185	static const char *bootfile = "boot.gz";
186	char bootdir[64];
187	unsigned int i;
188
189	if (!nobootfs) {
190		msg_fmt_display(msg_string(MSG_copybootloader), "%s",
191		    pm->diskdev);
192
193		snprintf(bootdir, sizeof(bootdir), "%s/boot",
194		    target_expand(PART_BOOT_MOUNT));
195		run_program(0, "/bin/mkdir -p %s", bootdir);
196		run_program(0, "/bin/cp /usr/mdec/boot %s", bootdir);
197		run_program(0, "/bin/rm -f %s/%s", bootdir, bootfile);
198		run_program(0, "/usr/bin/gzip -9 %s/boot", bootdir);
199		for (i = 0; i < __arraycount(kernels); i++)
200			run_program(0, "/bin/ln -fs %s %s/%s",
201			    bootfile, bootdir, kernels[i]);
202	}
203
204	return 0;
205}
206
207int
208md_post_extract(struct install_partition_desc *install, bool upgrade)
209{
210	return 0;
211}
212
213void
214md_cleanup_install(struct install_partition_desc *install)
215{
216#ifndef DEBUG
217	enable_rc_conf();
218#endif
219}
220
221int
222md_pre_update(struct install_partition_desc *install)
223{
224	size_t i;
225
226	/*
227	 * Verify the msdos partition exists and is big enough.
228	 */
229	for (i = 0; i < install->num; i++) {
230		if (install->infos[i].fs_type != PART_BOOT_TYPE)
231			continue;
232		if (install->infos[i].size/512 >= PART_BOOT_MIN)
233			break;
234		msg_display(MSG_boottoosmall);
235		msg_fmt_display_add(MSG_nobootpart, "%d", 0);
236		if (!ask_yesno(NULL))
237			return false;
238		nobootfs = 1;
239		break;
240	}
241
242	if (md_check_partitions(install) == 0)
243		nobootfs = 1;
244
245	return 1;
246}
247
248/* Upgrade support */
249int
250md_update(struct install_partition_desc *install)
251{
252	md_post_newfs(install);
253	return 1;
254}
255
256int
257md_check_mbr(struct disk_partitions *parts, mbr_info_t *mbri, bool quiet)
258{
259	mbr_info_t *ext;
260	struct mbr_partition *part;
261	int i;
262
263	for (ext = mbri; ext; ext = ext->extended) {
264		part = ext->mbr.mbr_parts;
265		for (i = 0; i < MBR_PART_COUNT; part++, i++) {
266			if (part->mbrp_type == MBR_PTYPE_LNXEXT2) {
267				pm->bootstart = part->mbrp_start;
268				pm->bootsize = part->mbrp_size;
269				break;
270			}
271		}
272	}
273	if (pm->bootsize < (PART_BOOT_MIN / 512)) {
274		if (quiet)
275			return 0;
276		msg_display(MSG_boottoosmall);
277		return ask_reedit(parts);
278	}
279	if (pm->bootstart == 0 || pm->bootsize == 0) {
280		if (quiet)
281			return 0;
282		msg_display(MSG_nobootpart);
283		return ask_reedit(parts);
284	}
285	return 2;
286}
287
288bool
289md_parts_use_wholedisk(struct disk_partitions *parts)
290{
291	struct disk_part_info boot_part = {
292		.size = PART_BOOT / 512,
293		.fs_type = PART_BOOT_TYPE,
294		.fs_sub_type = MBR_PTYPE_LNXEXT2,
295		.last_mounted = PART_BOOT_MOUNT,
296	};
297
298	boot_part.nat_type = parts->pscheme->get_fs_part_type(
299	    PT_EXT2, boot_part.fs_type, boot_part.fs_sub_type);
300
301	return parts_use_wholedisk(parts, 1, &boot_part);
302}
303
304int
305md_pre_mount(struct install_partition_desc *install, size_t ndx)
306{
307	return 0;
308}
309
310bool
311md_mbr_update_check(struct disk_partitions *parts, mbr_info_t *mbri)
312{
313	return false;	/* no change, no need to write back */
314}
315
316#ifdef HAVE_GPT
317bool
318md_gpt_post_write(struct disk_partitions *parts, part_id root_id,
319    bool root_is_new, part_id efi_id, bool efi_is_new)
320{
321	/* no GPT boot support, nothing needs to be done here */
322	return true;
323}
324#endif
325