md.c revision 1.2 1 /* $NetBSD: md.c,v 1.2 2014/08/03 16:09:39 martin 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 */
52 static int nobootfs = 0;
53 static int bootpart_ext2fs = PART_BOOT_EXT2FS;
54
55 void
56 md_init(void)
57 {
58 }
59
60 void
61 md_init_set_status(int flags)
62 {
63 (void)flags;
64 }
65
66 int
67 md_get_info(void)
68 {
69 return set_bios_geom_with_mbr_guess();
70 }
71
72 /*
73 * md back-end code for menu-driven BSD disklabel editor.
74 */
75 int
76 md_make_bsd_partitions(void)
77 {
78 int i;
79 int part;
80 int maxpart = getmaxpartitions();
81 int partstart;
82 int part_raw, part_bsd;
83 int ptend;
84 int no_swap = 0;
85 partinfo *p;
86
87 /*
88 * Initialize global variables that track space used on this disk.
89 * Standard 4.4BSD 8-partition labels always cover whole disk.
90 */
91 if (pm->ptsize == 0)
92 pm->ptsize = pm->dlsize - pm->ptstart;
93 if (pm->dlsize == 0)
94 pm->dlsize = pm->ptstart + pm->ptsize;
95
96 partstart = pm->ptstart;
97 ptend = pm->ptstart + pm->ptsize;
98
99 /* Ask for layout type -- standard or special */
100 msg_display(MSG_layout,
101 pm->ptsize / (MEG / pm->sectorsize),
102 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE,
103 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE + XNEEDMB);
104
105 process_menu(MENU_layout, NULL);
106
107 /* Set so we use the 'real' geometry for rounding, input in MB */
108 pm->current_cylsize = pm->dlcylsize;
109 set_sizemultname_meg();
110
111 /* Build standard partitions */
112 memset(&pm->bsdlabel, 0, sizeof pm->bsdlabel);
113
114 /* Set initial partition types to unused */
115 for (part = 0 ; part < maxpart ; ++part)
116 pm->bsdlabel[part].pi_fstype = FS_UNUSED;
117
118 /* Whole disk partition */
119 part_raw = getrawpartition();
120 if (part_raw == -1)
121 part_raw = PART_C; /* for sanity... */
122 pm->bsdlabel[part_raw].pi_offset = 0;
123 pm->bsdlabel[part_raw].pi_size = pm->dlsize;
124
125 if (part_raw == PART_D) {
126 /* Probably a system that expects an i386 style mbr */
127 part_bsd = PART_C;
128 pm->bsdlabel[PART_C].pi_offset = pm->ptstart;
129 pm->bsdlabel[PART_C].pi_size = pm->ptsize;
130 } else {
131 part_bsd = part_raw;
132 }
133
134 if (pm->bootsize != 0) {
135 pm->bsdlabel[PART_BOOT_EXT2FS].pi_fstype = FS_EX2FS;
136 pm->bsdlabel[PART_BOOT_EXT2FS].pi_size = pm->bootsize;
137 pm->bsdlabel[PART_BOOT_EXT2FS].pi_offset = pm->bootstart;
138 pm->bsdlabel[PART_BOOT_EXT2FS].pi_flags |=
139 PART_BOOT_EXT2FS_PI_FLAGS;
140 strlcpy(pm->bsdlabel[PART_BOOT_EXT2FS].pi_mount,
141 PART_BOOT_EXT2FS_PI_MOUNT,
142 sizeof pm->bsdlabel[PART_BOOT_EXT2FS].pi_mount);
143 }
144
145 #ifdef PART_REST
146 pm->bsdlabel[PART_REST].pi_offset = 0;
147 pm->bsdlabel[PART_REST].pi_size = pm->ptstart;
148 #endif
149
150 /*
151 * Save any partitions that are outside the area we are
152 * going to use.
153 * In particular this saves details of the other MBR
154 * partitions on a multiboot i386 system.
155 */
156 for (i = maxpart; i--;) {
157 if (pm->bsdlabel[i].pi_size != 0)
158 /* Don't overwrite special partitions */
159 continue;
160 p = &pm->oldlabel[i];
161 if (p->pi_fstype == FS_UNUSED || p->pi_size == 0)
162 continue;
163 if (layoutkind == LY_USEEXIST) {
164 if (PI_ISBSDFS(p))
165 p->pi_flags |= PIF_MOUNT;
166 } else {
167 if (p->pi_offset < pm->ptstart + pm->ptsize &&
168 p->pi_offset + p->pi_size > pm->ptstart)
169 /* Not outside area we are allocating */
170 continue;
171 if (p->pi_fstype == FS_SWAP)
172 no_swap = 1;
173 }
174 pm->bsdlabel[i] = pm->oldlabel[i];
175 }
176
177 if (layoutkind == LY_USEEXIST) {
178 /* XXX Check we have a sensible layout */
179 ;
180 } else
181 get_ptn_sizes(partstart, ptend - partstart, no_swap);
182
183 /*
184 * OK, we have a partition table. Give the user the chance to
185 * edit it and verify it's OK, or abort altogether.
186 */
187 edit_check:
188 if (edit_and_check_label(pm->bsdlabel, maxpart, part_raw, part_bsd) == 0) {
189 msg_display(MSG_abort);
190 return 0;
191 }
192 if (md_check_partitions() == 0)
193 goto edit_check;
194
195 /* Disk name */
196 msg_prompt(MSG_packname, pm->bsddiskname, pm->bsddiskname, sizeof pm->bsddiskname);
197
198 /* save label to disk for MI code to update. */
199 (void)savenewlabel(pm->bsdlabel, maxpart);
200
201 /* Everything looks OK. */
202 return 1;
203 }
204
205 /*
206 * any additional partition validation
207 */
208 int
209 md_check_partitions(void)
210 {
211 int part;
212
213 /* we need to find a boot partition, otherwise we can't write our
214 * bootloader. We make the assumption that the user hasn't done
215 * something stupid, like move it away from the MBR partition.
216 */
217 for (part = PART_A; part < MAXPARTITIONS; part++)
218 if (pm->bsdlabel[part].pi_fstype == FS_EX2FS) {
219 bootpart_ext2fs = part;
220 return 1;
221 }
222
223 msg_display(MSG_nobootpartdisklabel);
224 process_menu(MENU_ok, NULL);
225 return 0;
226 }
227
228 /*
229 * hook called before writing new disklabel.
230 */
231 int
232 md_pre_disklabel(void)
233 {
234 msg_display(MSG_dofdisk);
235
236 /* write edited MBR onto disk. */
237 if (write_mbr(pm->diskdev, &mbr, 1) != 0) {
238 msg_display(MSG_wmbrfail);
239 process_menu(MENU_ok, NULL);
240 return 1;
241 }
242 return 0;
243 }
244
245 /*
246 * hook called after writing disklabel to new target disk.
247 */
248 int
249 md_post_disklabel(void)
250 {
251 if (get_ramsize() <= 32)
252 set_swap(pm->diskdev, pm->bsdlabel);
253
254 return 0;
255 }
256
257 /*
258 * hook called after upgrade() or install() has finished setting
259 * up the target disk but immediately before the user is given the
260 * ``disks are now set up'' message.
261 */
262 int
263 md_post_newfs(void)
264 {
265 static const char *kernels[] = {
266 "vmlinux-nfsroot.gz",
267 "vmlinux.gz",
268 "vmlinux_RAQ.gz",
269 "vmlinux_raq-2800.gz"
270 };
271 static const char *bootfile = "boot.gz";
272 char bootdir[64];
273 unsigned int i;
274
275 if (!nobootfs) {
276 msg_display(msg_string(MSG_copybootloader), pm->diskdev);
277
278 snprintf(bootdir, sizeof(bootdir), "%s/boot",
279 target_expand(PART_BOOT_EXT2FS_PI_MOUNT));
280 run_program(0, "/bin/mkdir -p %s", bootdir);
281 run_program(0, "/bin/cp /usr/mdec/boot %s", bootdir);
282 run_program(0, "/bin/rm -f %s/%s", bootdir, bootfile);
283 run_program(0, "/usr/bin/gzip -9 %s/boot", bootdir);
284 for (i = 0; i < __arraycount(kernels); i++)
285 run_program(0, "/bin/ln -fs %s %s/%s",
286 bootfile, bootdir, kernels[i]);
287 }
288
289 return 0;
290 }
291
292 int
293 md_post_extract(void)
294 {
295 return 0;
296 }
297
298 void
299 md_cleanup_install(void)
300 {
301 #ifndef DEBUG
302 enable_rc_conf();
303 #endif
304 }
305
306 int
307 md_pre_update(void)
308 {
309 struct mbr_partition *part;
310 mbr_info_t *ext;
311 int i;
312
313 if (get_ramsize() <= 32)
314 set_swap(pm->diskdev, NULL);
315
316 read_mbr(pm->diskdev, &mbr);
317 /* do a sanity check of the partition table */
318 for (ext = &mbr; ext; ext = ext->extended) {
319 part = ext->mbr.mbr_parts;
320 for (i = 0; i < MBR_PART_COUNT; part++, i++) {
321 if (part->mbrp_type != MBR_PTYPE_LNXEXT2)
322 continue;
323 if (part->mbrp_size < (MIN_EXT2FS_BOOT / 512)) {
324 msg_display(MSG_boottoosmall);
325 msg_display_add(MSG_nobootpart, 0);
326 process_menu(MENU_yesno, NULL);
327 if (!yesno)
328 return 0;
329 nobootfs = 1;
330 }
331 }
332 }
333 if (md_check_partitions() == 0)
334 nobootfs = 1;
335 return 1;
336 }
337
338 /* Upgrade support */
339 int
340 md_update(void)
341 {
342 md_post_newfs();
343 return 1;
344 }
345
346 int
347 md_check_mbr(mbr_info_t *mbri)
348 {
349 mbr_info_t *ext;
350 struct mbr_partition *part;
351 int i;
352
353 for (ext = mbri; ext; ext = ext->extended) {
354 part = ext->mbr.mbr_parts;
355 for (i = 0; i < MBR_PART_COUNT; part++, i++) {
356 if (part->mbrp_type == MBR_PTYPE_LNXEXT2) {
357 pm->bootstart = part->mbrp_start;
358 pm->bootsize = part->mbrp_size;
359 break;
360 }
361 }
362 }
363 if (pm->bootsize < (MIN_EXT2FS_BOOT / 512)) {
364 msg_display(MSG_boottoosmall);
365 msg_display_add(MSG_reeditpart, 0);
366 process_menu(MENU_yesno, NULL);
367 if (!yesno)
368 return 0;
369 return 1;
370 }
371 if (pm->bootstart == 0 || pm->bootsize == 0) {
372 msg_display(MSG_nobootpart);
373 msg_display_add(MSG_reeditpart, 0);
374 process_menu(MENU_yesno, NULL);
375 if (!yesno)
376 return 0;
377 return 1;
378 }
379 return 2;
380 }
381
382 int
383 md_mbr_use_wholedisk(mbr_info_t *mbri)
384 {
385 struct mbr_sector *mbrs = &mbri->mbr;
386 mbr_info_t *ext;
387 struct mbr_partition *part;
388
389 part = &mbrs->mbr_parts[0];
390 /* Set the partition information for full disk usage. */
391 while ((ext = mbri->extended)) {
392 mbri->extended = ext->extended;
393 free(ext);
394 }
395 memset(part, 0, MBR_PART_COUNT * sizeof *part);
396 #ifdef BOOTSEL
397 memset(&mbri->mbrb, 0, sizeof mbri->mbrb);
398 #endif
399 part[0].mbrp_type = MBR_PTYPE_LNXEXT2;
400 part[0].mbrp_size = EXT2FS_BOOT_SIZE / 512;
401 part[0].mbrp_start = bsec;
402 part[0].mbrp_flag = MBR_PFLAG_ACTIVE;
403
404 part[1].mbrp_type = MBR_PTYPE_NETBSD;
405 part[1].mbrp_size = pm->dlsize - (bsec + EXT2FS_BOOT_SIZE / 512);
406 part[1].mbrp_start = bsec + EXT2FS_BOOT_SIZE / 512;
407 part[1].mbrp_flag = 0;
408
409 pm->ptstart = part[1].mbrp_start;
410 pm->ptsize = part[1].mbrp_size;
411 pm->bootstart = part[0].mbrp_start;
412 pm->bootsize = part[0].mbrp_size;
413 return 1;
414 }
415
416 int
417 md_pre_mount()
418 {
419 return 0;
420 }
421