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