md.c revision 1.4 1 /* $NetBSD: md.c,v 1.4 2019/06/12 06:20:22 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 -- ofppc machine specific routines */
36
37 #include <sys/param.h>
38 #include <sys/sysctl.h>
39 #include <sys/disklabel_rdb.h>
40 #include <stdio.h>
41 #include <util.h>
42 #include <machine/cpu.h>
43
44 #include "defs.h"
45 #include "md.h"
46 #include "msg_defs.h"
47 #include "menu_defs.h"
48 #include "endian.h"
49
50 static int check_rdb(void);
51 static uint32_t rdbchksum(void *);
52
53 /* We use MBR_PTYPE_PREP like port-prep does. */
54 static int nonewfsmsdos = 0, nobootfix = 0, noprepfix=0;
55 static part_id bootpart_fat12 = NO_PART, bootpart_binfo = NO_PART,
56 bootpart_prep = NO_PART;
57 static int bootinfo_mbr = 1;
58 static int rdb_found = 0;
59
60 /* bootstart/bootsize are for the fat */
61 int binfostart, binfosize, bprepstart, bprepsize;
62
63 void
64 md_init(void)
65 {
66 }
67
68 void
69 md_init_set_status(int flags)
70 {
71
72 (void)flags;
73 }
74
75 bool
76 md_get_info(struct install_partition_desc *install)
77 {
78
79 if (check_rdb())
80 return true;
81
82 return set_bios_geom_with_mbr_guess(pm->parts);
83 }
84
85 /*
86 * md back-end code for menu-driven BSD disklabel editor.
87 */
88 bool
89 md_make_bsd_partitions(struct install_partition_desc *install)
90 {
91 #if 0
92 int i;
93 int part;
94 int maxpart = getmaxpartitions();
95 int partstart;
96 int part_raw, part_bsd;
97 int ptend;
98 int no_swap = 0;
99 #endif
100
101 if (rdb_found) {
102 #if 0
103 /*
104 * XXX - need to test on real machine if the disklabel code
105 * deals with RDB partitions properly, otherwise write
106 * a read-only RDB backend
107 */
108 /*
109 * We found RDB partitions on the disk, which cannot be
110 * modified by rewriting the disklabel.
111 * So just use what we have got.
112 */
113 for (part = 0; part < maxpart; part++) {
114 if (PI_ISBSDFS(&pm->bsdlabel[part])) {
115 pm->bsdlabel[part].pi_flags |=
116 PIF_NEWFS | PIF_MOUNT;
117
118 if (part == PART_A)
119 strcpy(pm->bsdlabel[part].pi_mount, "/");
120 }
121 }
122
123 part_bsd = part_raw = getrawpartition();
124 if (part_raw == -1)
125 part_raw = PART_C; /* for sanity... */
126 pm->bsdlabel[part_raw].pi_offset = 0;
127 pm->bsdlabel[part_raw].pi_size = pm->dlsize;
128
129 set_sizemultname_meg();
130 rdb_edit_check:
131 if (edit_and_check_label(pm->bsdlabel, maxpart, part_raw,
132 part_bsd) == 0) {
133 msg_display(MSG_abort);
134 return 0;
135 }
136 if (md_check_partitions() == 0)
137 goto rdb_edit_check;
138 #endif
139 return 1;
140 }
141
142 /*
143 * Initialize global variables that track space used on this disk.
144 * Standard 4.4BSD 8-partition labels always cover whole disk.
145 */
146 if (pm->ptsize == 0)
147 pm->ptsize = pm->dlsize - pm->ptstart;
148 if (pm->dlsize == 0)
149 pm->dlsize = pm->ptstart + pm->ptsize;
150
151 #if 0
152 partstart = pm->ptstart;
153 ptend = pm->ptstart + pm->ptsize;
154
155 /* Ask for layout type -- standard or special */
156 msg_display(MSG_layout,
157 pm->ptsize / (MEG / pm->sectorsize),
158 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE,
159 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE + XNEEDMB);
160
161 process_menu(MENU_layout, NULL);
162
163 /* Set so we use the 'real' geometry for rounding, input in MB */
164 pm->current_cylsize = pm->dlcylsize;
165 set_sizemultname_meg();
166
167 /* Build standard partitions */
168 memset(&pm->bsdlabel, 0, sizeof pm->bsdlabel);
169
170 /* Set initial partition types to unused */
171 for (part = 0 ; part < maxpart ; ++part)
172 pm->bsdlabel[part].pi_fstype = FS_UNUSED;
173
174 /* Whole disk partition */
175 part_raw = getrawpartition();
176 if (part_raw == -1)
177 part_raw = PART_C; /* for sanity... */
178 pm->bsdlabel[part_raw].pi_offset = 0;
179 pm->bsdlabel[part_raw].pi_size = pm->dlsize;
180
181 if (part_raw == PART_D) {
182 /* Probably a system that expects an i386 style mbr */
183 part_bsd = PART_C;
184 pm->bsdlabel[PART_C].pi_offset = pm->ptstart;
185 pm->bsdlabel[PART_C].pi_size = pm->ptsize;
186 } else {
187 part_bsd = part_raw;
188 }
189
190 if (pm->bootsize != 0) {
191 pm->bsdlabel[PART_BOOT_FAT12].pi_fstype = FS_MSDOS;
192 pm->bsdlabel[PART_BOOT_FAT12].pi_size = pm->bootsize;
193 pm->bsdlabel[PART_BOOT_FAT12].pi_offset = pm->bootstart;
194 pm->bsdlabel[PART_BOOT_FAT12].pi_flags |= PART_BOOT_FAT12_PI_FLAGS;
195 strlcpy(pm->bsdlabel[PART_BOOT_FAT12].pi_mount,
196 PART_BOOT_FAT12_PI_MOUNT,
197 sizeof pm->bsdlabel[PART_BOOT_FAT12].pi_mount);
198 }
199 if (binfosize != 0) {
200 pm->bsdlabel[PART_BOOT_BINFO].pi_fstype = FS_OTHER;
201 pm->bsdlabel[PART_BOOT_BINFO].pi_size = binfosize;
202 pm->bsdlabel[PART_BOOT_BINFO].pi_offset = binfostart;
203 }
204 if (bprepsize != 0) {
205 pm->bsdlabel[PART_BOOT_PREP].pi_fstype = FS_BOOT;
206 pm->bsdlabel[PART_BOOT_PREP].pi_size = bprepsize;
207 pm->bsdlabel[PART_BOOT_PREP].pi_offset = bprepstart;
208 }
209
210 #ifdef PART_REST
211 pm->bsdlabel[PART_REST].pi_offset = 0;
212 pm->bsdlabel[PART_REST].pi_size = pm->ptstart;
213 #endif
214
215 /*
216 * Save any partitions that are outside the area we are
217 * going to use.
218 * In particular this saves details of the other MBR
219 * partitions on a multiboot i386 system.
220 */
221 for (i = maxpart; i--;) {
222 if (pm->bsdlabel[i].pi_size != 0)
223 /* Don't overwrite special partitions */
224 continue;
225 p = &pm->oldlabel[i];
226 if (p->pi_fstype == FS_UNUSED || p->pi_size == 0)
227 continue;
228 if (layoutkind == LY_USEEXIST) {
229 if (PI_ISBSDFS(p))
230 p->pi_flags |= PIF_MOUNT;
231 } else {
232 if (p->pi_offset < pm->ptstart + pm->ptsize &&
233 p->pi_offset + p->pi_size > pm->ptstart)
234 /* Not outside area we are allocating */
235 continue;
236 if (p->pi_fstype == FS_SWAP)
237 no_swap = 1;
238 }
239 pm->bsdlabel[i] = pm->oldlabel[i];
240 }
241
242 if (layoutkind == LY_USEEXIST) {
243 /* XXX Check we have a sensible layout */
244 ;
245 } else
246 get_ptn_sizes(partstart, ptend - partstart, no_swap);
247
248 /*
249 * OK, we have a partition table. Give the user the chance to
250 * edit it and verify it's OK, or abort altogether.
251 */
252 edit_check:
253 if (edit_and_check_label(pm->bsdlabel, maxpart, part_raw, part_bsd) == 0) {
254 msg_display(MSG_abort);
255 return 0;
256 }
257 if (md_check_partitions() == 0)
258 goto edit_check;
259
260 /* Disk name */
261 msg_prompt(MSG_packname, pm->bsddiskname, pm->bsddiskname, sizeof pm->bsddiskname);
262
263 /* save label to disk for MI code to update. */
264 (void) savenewlabel(pm->bsdlabel, maxpart);
265
266 /* Everything looks OK. */
267 return 1;
268 #endif
269
270 return make_bsd_partitions(install);
271 }
272
273 /*
274 * any additional partition validation
275 */
276 bool
277 md_check_partitions(struct install_partition_desc *install)
278 {
279 struct disk_partitions *parts;
280 struct disk_part_info info;
281 int fprep=0, ffat=0;
282 part_id part;
283
284 if (rdb_found)
285 return 1;
286
287 if (install->num < 1)
288 return false;
289 parts = install->infos[0].parts; /* disklabel parts */
290 if (parts->parent)
291 parts = parts->parent; /* MBR parts */
292
293 /* we need to find a boot partition, otherwise we can't create
294 * our msdos fs boot partition. We make the assumption that
295 * the user hasn't done something stupid, like move it away
296 * from the MBR partition.
297 */
298 for (part = 0; part < parts->num_part; part++) {
299 if (!parts->pscheme->get_part_info(parts, part, &info))
300 continue;
301
302 if (info.fs_type == FS_MSDOS) {
303 bootpart_fat12 = part;
304 ffat++;
305 } else if (info.fs_type == FS_BOOT) {
306 bootpart_prep = part;
307 fprep++;
308 } else if (info.fs_type == FS_OTHER) {
309 bootpart_binfo = part;
310 fprep++;
311 }
312 }
313 /* oh, the confusion */
314 if (ffat >= 1 && fprep < 2) {
315 noprepfix = 1;
316 return true;
317 }
318 if (ffat < 1 && fprep >= 2) {
319 nobootfix = 1;
320 return true;
321 }
322 if (ffat >=1 && fprep >= 2) {
323 return true;
324 }
325
326 msg_display(MSG_nobootpartdisklabel);
327 process_menu(MENU_ok, NULL);
328 nobootfix = 1;
329 return false;
330 }
331
332 /*
333 * hook called before writing new disklabel.
334 */
335 bool
336 md_pre_disklabel(struct install_partition_desc *install,
337 struct disk_partitions *parts)
338 {
339
340 if (rdb_found)
341 return true;
342
343
344 if (parts->parent == NULL)
345 return true; /* no outer partitions */
346
347 parts = parts->parent;
348
349 msg_display_subst(MSG_dofdisk, 3, parts->disk,
350 msg_string(parts->pscheme->name),
351 msg_string(parts->pscheme->short_name));
352
353 /* write edited "MBR" onto disk. */
354 if (!parts->pscheme->write_to_disk(parts)) {
355 msg_display(MSG_wmbrfail);
356 process_menu(MENU_ok, NULL);
357 return false;
358 }
359 return true;
360 }
361
362 /*
363 * hook called after writing disklabel to new target disk.
364 */
365 bool
366 md_post_disklabel(struct install_partition_desc *install,
367 struct disk_partitions *parts)
368 {
369 char bootdev[100];
370
371 if (pm->bootstart == 0 || pm->bootsize == 0 || rdb_found)
372 return 0;
373
374 snprintf(bootdev, sizeof bootdev, "/dev/r%s%c", pm->diskdev,
375 'a'+bootpart_fat12);
376 run_program(RUN_DISPLAY, "/sbin/newfs_msdos %s", bootdev);
377
378 return 0;
379 }
380
381 /*
382 * hook called after upgrade() or install() has finished setting
383 * up the target disk but immediately before the user is given the
384 * ``disks are now set up'' message.
385 */
386 int
387 md_post_newfs(struct install_partition_desc *install)
388 {
389
390 /* No bootblock. We use ofwboot from a partition visiable by OFW. */
391 return 0;
392 }
393
394 int
395 md_post_extract(struct install_partition_desc *install)
396 {
397 char bootdev[100], bootbdev[100], version[64];
398 struct disk_partitions *parts;
399
400 /* if we can't make it bootable, just punt */
401 if ((nobootfix && noprepfix) || rdb_found)
402 return 0;
403
404 snprintf(version, sizeof version, "NetBSD/%s %s", MACH, REL);
405 run_program(RUN_DISPLAY, "/usr/mdec/mkbootinfo '%s' %d "
406 "/tmp/bootinfo.txt", version, bootinfo_mbr);
407
408 if (!nobootfix) {
409 run_program(RUN_DISPLAY, "/bin/mkdir -p /%s/boot/ppc",
410 target_prefix());
411 run_program(RUN_DISPLAY, "/bin/mkdir -p /%s/boot/netbsd",
412 target_prefix());
413 run_program(RUN_DISPLAY, "/bin/cp /usr/mdec/ofwboot "
414 "/%s/boot/netbsd", target_prefix());
415 run_program(RUN_DISPLAY, "/bin/cp /tmp/bootinfo.txt "
416 "/%s/boot/ppc", target_prefix());
417 run_program(RUN_DISPLAY, "/bin/cp /usr/mdec/ofwboot "
418 "/%s/boot/ofwboot", target_prefix());
419 }
420
421 if (!noprepfix && install != NULL && install->num > 0) {
422 parts = install->infos[0].parts; /* disklabel */
423 if (parts->parent != NULL)
424 parts = parts->parent; /* MBR */
425
426 parts->pscheme->get_part_device(parts, bootpart_prep,
427 bootdev, sizeof bootdev, NULL, raw_dev_name, true);
428 parts->pscheme->get_part_device(parts, bootpart_prep,
429 bootbdev, sizeof bootbdev, NULL, plain_name, true);
430 run_program(RUN_DISPLAY, "/bin/dd if=/dev/zero of=%s bs=512",
431 bootdev);
432 run_program(RUN_DISPLAY, "/bin/dd if=/usr/mdec/ofwboot "
433 "of=%s bs=512", bootbdev);
434
435 parts->pscheme->get_part_device(parts, bootpart_binfo,
436 bootdev, sizeof bootdev, NULL, raw_dev_name, true);
437 parts->pscheme->get_part_device(parts, bootpart_binfo,
438 bootbdev, sizeof bootbdev, NULL, plain_name, true);
439 run_program(RUN_DISPLAY, "/bin/dd if=/dev/zero of=%s bs=512",
440 bootdev);
441 run_program(RUN_DISPLAY, "/bin/dd if=/tmp/bootinfo.txt "
442 "of=%s bs=512", bootbdev);
443 }
444
445 return 0;
446 }
447
448 void
449 md_cleanup_install(struct install_partition_desc *install)
450 {
451
452 #ifndef DEBUG
453 enable_rc_conf();
454 #endif
455 }
456
457 int
458 md_pre_update(struct install_partition_desc *install)
459 {
460 #if 0
461 struct mbr_partition *part;
462 mbr_info_t *ext;
463 int i;
464 #endif
465
466 if (check_rdb())
467 return 1;
468
469 #if 0
470 read_mbr(pm->diskdev, &mbr);
471 /* do a sanity check of the partition table */
472 for (ext = &mbr; ext; ext = ext->extended) {
473 part = ext->mbr.mbr_parts;
474 for (i = 0; i < MBR_PART_COUNT; part++, i++) {
475 if (part->mbrp_type == MBR_PTYPE_PREP &&
476 part->mbrp_size > 50)
477 bootinfo_mbr = i+1;
478 if (part->mbrp_type == MBR_PTYPE_RESERVED_x21 &&
479 part->mbrp_size < (MIN_FAT12_BOOT/512)) {
480 msg_display(MSG_boottoosmall);
481 msg_display_add(MSG_nobootpartdisklabel, 0);
482 if (!ask_yesno(NULL))
483 return 0;
484 nobootfix = 1;
485 }
486 }
487 }
488 #endif
489
490 if (!md_check_partitions(install))
491 return 0;
492
493 return 1;
494 }
495
496 /* Upgrade support */
497 int
498 md_update(struct install_partition_desc *install)
499 {
500
501 nonewfsmsdos = 1;
502 md_post_newfs(install);
503 return 1;
504 }
505
506
507 int
508 md_check_mbr(struct disk_partitions *parts, mbr_info_t *mbri, bool quiet)
509 {
510 mbr_info_t *ext;
511 struct mbr_partition *part;
512 int i;
513
514 for (ext = mbri; ext; ext = ext->extended) {
515 part = ext->mbr.mbr_parts;
516 for (i = 0; i < MBR_PART_COUNT; part++, i++) {
517 if (part->mbrp_type == MBR_PTYPE_FAT12) {
518 pm->bootstart = part->mbrp_start;
519 pm->bootsize = part->mbrp_size;
520 } else if (part->mbrp_type == MBR_PTYPE_PREP &&
521 part->mbrp_size < 50) {
522 /* this is the bootinfo partition */
523 binfostart = part->mbrp_start;
524 binfosize = part->mbrp_size;
525 bootinfo_mbr = i+1;
526 } else if (part->mbrp_type == MBR_PTYPE_PREP &&
527 part->mbrp_size > 50) {
528 bprepstart = part->mbrp_start;
529 bprepsize = part->mbrp_size;
530 }
531 break;
532 }
533 }
534
535 /* we need to either have a pair of prep partitions, or a single
536 * fat. if neither, things are broken. */
537 if (!(pm->bootsize >= (MIN_FAT12_BOOT/512) ||
538 (binfosize >= (MIN_BINFO_BOOT/512) &&
539 bprepsize >= (MIN_PREP_BOOT/512)))) {
540 if (quiet)
541 return 0;
542 msg_display(MSG_bootnotright);
543 return ask_reedit(parts);
544 }
545
546 /* check the prep partitions */
547 if ((binfosize > 0 || bprepsize > 0) &&
548 (binfosize < (MIN_BINFO_BOOT/512) ||
549 bprepsize < (MIN_PREP_BOOT/512))) {
550 if (quiet)
551 return 0;
552 msg_display(MSG_preptoosmall);
553 return ask_reedit(parts);
554 }
555
556 /* check the fat12 parititons */
557 if (pm->bootsize > 0 && pm->bootsize < (MIN_FAT12_BOOT/512)) {
558 if (quiet)
559 return 0;
560 msg_display(MSG_boottoosmall);
561 return ask_reedit(parts);
562 }
563
564 /* if both sets contain zero, thats bad */
565 if ((pm->bootstart == 0 || pm->bootsize == 0) &&
566 (binfosize == 0 || binfostart == 0 ||
567 bprepsize == 0 || bprepstart == 0)) {
568 if (quiet)
569 return 0;
570 msg_display(MSG_nobootpart);
571 return ask_reedit(parts);
572 }
573 return 2;
574 }
575
576 /*
577 * NOTE, we use a reserved partition type, because some RS/6000 machines hang
578 * hard if they find a FAT12, and if we use type prep, that indicates that
579 * it should be read raw.
580 * One partition for FAT12 booting
581 * One partition for NetBSD
582 * One partition to hold the bootinfo.txt file
583 * One partition to hold ofwboot
584 */
585
586 bool
587 md_parts_use_wholedisk(struct disk_partitions *parts)
588 {
589 struct disk_part_info boot_parts[] =
590 {
591 { .fs_type = FS_MSDOS, .size = FAT12_BOOT_SIZE/512 },
592 { .fs_type = FS_OTHER, .size = BINFO_BOOT_SIZE/512 },
593 { .fs_type = FS_BOOT, .size = PREP_BOOT_SIZE/512 }
594 };
595
596 return parts_use_wholedisk(parts, __arraycount(boot_parts),
597 boot_parts);
598 }
599
600 const char *md_disklabel_cmd(void)
601 {
602
603 /* we cannot rewrite an RDB disklabel */
604 if (rdb_found)
605 return "sync No disklabel";
606
607 return "disklabel -w -r";
608 }
609
610 static int
611 check_rdb(void)
612 {
613 char buf[512], diskpath[MAXPATHLEN];
614 struct rdblock *rdb;
615 off_t blk;
616 int fd;
617
618 /* Find out if this disk has a valid RDB, before continuing. */
619 rdb = (struct rdblock *)buf;
620 fd = opendisk(pm->diskdev, O_RDONLY, diskpath, sizeof(diskpath), 0);
621 if (fd < 0)
622 return 0;
623 for (blk = 0; blk < RDB_MAXBLOCKS; blk++) {
624 if (pread(fd, rdb, 512, blk * 512) != 512)
625 return 0;
626 if (rdb->id == RDBLOCK_ID && rdbchksum(rdb) == 0) {
627 rdb_found = 1; /* do not repartition! */
628 return 1;
629 }
630 }
631 return 0;
632 }
633
634 static uint32_t
635 rdbchksum(void *bdata)
636 {
637 uint32_t *blp, cnt, val;
638
639 blp = bdata;
640 cnt = blp[1];
641 val = 0;
642 while (cnt--)
643 val += *blp++;
644 return val;
645 }
646
647 int
648 md_pre_mount(struct install_partition_desc *install)
649 {
650
651 return 0;
652 }
653
654 bool
655 md_mbr_update_check(struct disk_partitions *parts, mbr_info_t *mbri)
656 {
657 return false; /* no change, no need to write back */
658 }
659
660 #ifdef HAVE_GPT
661 bool
662 md_gpt_post_write(struct disk_partitions *parts, part_id root_id,
663 bool root_is_new, part_id efi_id, bool efi_is_new)
664 {
665 /* no GPT boot support, nothing needs to be done here */
666 return true;
667 }
668 #endif
669
670