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