Annotation of src/usr.sbin/sysinst/arch/i386/md.c, Revision 1.10
1.10 ! martin 1: /* $NetBSD: md.c,v 1.9 2018/06/03 13:16:30 martin Exp $ */
1.1 dholland 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 -- i386 machine specific routines - also used by amd64 */
36:
37: #include <sys/param.h>
38: #include <sys/sysctl.h>
39: #include <sys/exec.h>
40: #include <sys/utsname.h>
41: #include <sys/types.h>
42: #include <sys/stat.h>
43: #include <machine/cpu.h>
44: #include <stdio.h>
45: #include <stddef.h>
46: #include <util.h>
47: #include <dirent.h>
48: #include <termios.h>
49:
50: #include "defs.h"
51: #include "md.h"
52: #include "endian.h"
53: #include "msg_defs.h"
54: #include "menu_defs.h"
55:
56: #ifdef NO_LBA_READS /* for testing */
57: #undef BIFLAG_EXTINT13
58: #define BIFLAG_EXTINT13 0
59: #endif
60:
61: static struct biosdisk_info *biosdisk = NULL;
62:
63: /* prototypes */
64:
65: static int get_bios_info(char *);
66: static int mbr_root_above_chs(void);
67: static void md_upgrade_mbrtype(void);
68: static int md_read_bootcode(const char *, struct mbr_sector *);
69: static unsigned int get_bootmodel(void);
70:
71: void
72: md_init(void)
73: {
74: }
75:
76: void
77: md_init_set_status(int flags)
78: {
79: (void)flags;
80:
81: /* Default to install same type of kernel as we are running */
82: set_kernel_set(get_bootmodel());
83: }
84:
85: int
86: md_get_info(void)
87: {
88: mbr_info_t *ext;
89: struct mbr_partition *p;
90: const char *bootcode;
91: int i;
92: int names, fl, ofl;
93: #define ACTIVE_FOUND 0x0100
94: #define NETBSD_ACTIVE 0x0200
95: #define NETBSD_NAMED 0x0400
96: #define ACTIVE_NAMED 0x0800
97:
1.2 martin 98: if (pm->no_mbr)
1.1 dholland 99: return 1;
100:
1.2 martin 101: if (read_mbr(pm->diskdev, &mbr) < 0)
1.1 dholland 102: memset(&mbr.mbr, 0, sizeof mbr.mbr - 2);
1.2 martin 103: get_bios_info(pm->diskdev);
1.1 dholland 104:
105: edit:
106: if (edit_mbr(&mbr) == 0)
107: return 0;
108:
109: root_limit = 0;
110: if (biosdisk != NULL && (biosdisk->bi_flags & BIFLAG_EXTINT13) == 0) {
111: if (mbr_root_above_chs()) {
112: msg_display(MSG_partabovechs);
1.6 martin 113: if (!ask_noyes(NULL))
1.1 dholland 114: goto edit;
115: /* The user is shooting themselves in the foot here...*/
116: } else
117: root_limit = bcyl * bhead * bsec;
118: }
119:
120: /*
1.2 martin 121: * Ensure the install partition (at sector pm->ptstart) and the active
1.1 dholland 122: * partition are bootable.
123: * Determine whether the bootselect code is needed.
124: * Note that MBR_BS_NEWMBR is always set, so we ignore it!
125: */
126: fl = 0;
127: names = 0;
128: for (ext = &mbr; ext != NULL; ext = ext->extended) {
129: p = ext->mbr.mbr_parts;
130: for (i = 0; i < MBR_PART_COUNT; p++, i++) {
131: if (p->mbrp_flag == MBR_PFLAG_ACTIVE) {
132: fl |= ACTIVE_FOUND;
1.2 martin 133: if (ext->sector + p->mbrp_start == pm->ptstart)
1.1 dholland 134: fl |= NETBSD_ACTIVE;
135: }
136: if (ext->mbrb.mbrbs_nametab[i][0] == 0) {
137: /* No bootmenu label... */
138: if (ext->sector == 0)
139: continue;
1.2 martin 140: if (ext->sector + p->mbrp_start == pm->ptstart)
1.1 dholland 141: /*
142: * Have installed into an extended ptn
143: * force name & bootsel...
144: */
145: names++;
146: continue;
147: }
148: /* Partition has a bootmenu label... */
149: if (ext->sector != 0)
150: fl |= MBR_BS_EXTLBA;
1.2 martin 151: if (ext->sector + p->mbrp_start == pm->ptstart)
1.1 dholland 152: fl |= NETBSD_NAMED;
153: else if (p->mbrp_flag == MBR_PFLAG_ACTIVE)
154: fl |= ACTIVE_NAMED;
155: else
156: names++;
157: }
158: }
159: if (!(fl & ACTIVE_FOUND))
160: fl |= NETBSD_ACTIVE;
161: if (fl & NETBSD_NAMED && fl & NETBSD_ACTIVE)
162: fl |= ACTIVE_NAMED;
163:
164: if ((names > 0 || !(fl & NETBSD_ACTIVE)) &&
165: (!(fl & NETBSD_NAMED) || !(fl & ACTIVE_NAMED))) {
166: /*
167: * There appear to be multiple bootable partitions, but they
168: * don't all have bootmenu texts.
169: */
170: msg_display(MSG_missing_bootmenu_text);
1.6 martin 171: if (ask_yesno(NULL))
1.1 dholland 172: goto edit;
173: }
174:
175: if ((fl & MBR_BS_EXTLBA) &&
176: (biosdisk == NULL || !(biosdisk->bi_flags & BIFLAG_EXTINT13))) {
177: /* Need unsupported LBA reads to read boot sectors */
178: msg_display(MSG_no_extended_bootmenu);
1.6 martin 179: if (!ask_noyes(NULL))
1.1 dholland 180: goto edit;
181: }
182:
183: /* Sort out the name of the mbr code we need */
184: if (names > 0 || fl & (NETBSD_NAMED | ACTIVE_NAMED)) {
185: /* Need bootselect code */
186: fl |= MBR_BS_ACTIVE;
187: bootcode = fl & MBR_BS_EXTLBA ? _PATH_BOOTEXT : _PATH_BOOTSEL;
188: } else
189: bootcode = _PATH_MBR;
190:
191: fl &= MBR_BS_ACTIVE | MBR_BS_EXTLBA;
192:
193: /* Look at what is installed */
194: ofl = mbr.mbrb.mbrbs_flags;
195: if (ofl == 0) {
196: /* Check there is some bootcode at all... */
197: if (mbr.mbr.mbr_magic != htole16(MBR_MAGIC) ||
198: mbr.mbr.mbr_jmpboot[0] == 0 ||
199: mbr_root_above_chs())
200: /* Existing won't do, force update */
201: fl |= MBR_BS_NEWMBR;
202: }
203: ofl = mbr.oflags & (MBR_BS_ACTIVE | MBR_BS_EXTLBA);
204:
205: if (fl & ~ofl || (fl == 0 && ofl & MBR_BS_ACTIVE)) {
206: /* Existing boot code isn't the right one... */
207: if (fl & MBR_BS_ACTIVE)
208: msg_display(MSG_installbootsel);
209: else
210: msg_display(MSG_installmbr);
211: } else
212: /* Existing code would (probably) be ok */
213: msg_display(MSG_updatembr);
214:
1.6 martin 215: if (!ask_yesno(NULL))
1.1 dholland 216: /* User doesn't want to update mbr code */
217: return 1;
218:
219: if (md_read_bootcode(bootcode, &mbr.mbr) == 0)
220: /* update suceeded - to memory copy */
221: return 1;
222:
223: /* This shouldn't happen since the files are in the floppy fs... */
224: msg_display("Can't find %s", bootcode);
1.6 martin 225: ask_yesno(NULL);
1.1 dholland 226:
227: return 1;
228: }
229:
230: /*
231: * md back-end code for menu-driven BSD disklabel editor.
232: */
233: int
234: md_make_bsd_partitions(void)
235: {
236: return make_bsd_partitions();
237: }
238:
239: /*
240: * any additional partition validation
241: */
242: int
243: md_check_partitions(void)
244: {
245: int rval;
246: char *bootxx;
247:
248: /* check we have boot code for the root partition type */
249: bootxx = bootxx_name();
250: rval = access(bootxx, R_OK);
251: free(bootxx);
252: if (rval == 0)
253: return 1;
1.8 joerg 254: process_menu(MENU_ok, __UNCONST(MSG_No_Bootcode));
1.1 dholland 255: return 0;
256: }
257:
258: /*
259: * hook called before writing new disklabel.
260: */
261: int
262: md_pre_disklabel(void)
263: {
1.2 martin 264: if (pm->no_mbr)
1.1 dholland 265: return 0;
266:
267: msg_display(MSG_dofdisk);
268:
269: /* write edited MBR onto disk. */
1.2 martin 270: if (write_mbr(pm->diskdev, &mbr, 1) != 0) {
1.1 dholland 271: msg_display(MSG_wmbrfail);
272: process_menu(MENU_ok, NULL);
273: return 1;
274: }
275: return 0;
276: }
277:
278: /*
279: * hook called after writing disklabel to new target disk.
280: */
281: int
282: md_post_disklabel(void)
283: {
284: return 0;
285: }
286:
287: /*
288: * hook called after upgrade() or install() has finished setting
289: * up the target disk but immediately before the user is given the
290: * ``disks are now set up'' message.
291: */
292: int
293: md_post_newfs(void)
294: {
295: int ret;
296: size_t len;
1.3 riz 297: char boot_options[1024];
1.1 dholland 298: char *bootxx_filename;
299: /*
1.3 riz 300: * XXX - this code retains a lot of cruft from when we went
301: * to great pains to exclude installboot from the ramdisk
302: * for size reasons and should be rewritten.
1.1 dholland 303: */
1.3 riz 304: static const char *consoles[]={
305: "pc", /* CONSDEV_PC */
306: "com0", /* CONSDEV_COM0 */
307: "com1", /* CONSDEV_COM1 */
308: "com2", /* CONSDEV_COM2 */
309: "com3", /* CONSDEV_COM3 */
310: "com0kbd", /* CONSDEV_COM0KBD */
311: "com1kbd", /* CONSDEV_COM1KBD */
312: "com2kbd", /* CONSDEV_COM2KBD */
313: "com3kbd" /* CONSDEV_COM3KBD */ };
1.1 dholland 314: static struct x86_boot_params boottype =
315: {sizeof boottype, 0, 5, 0, 9600, { '\0' }, "", 0};
316: static int conmib[] = {CTL_MACHDEP, CPU_CONSDEV};
317: struct termios t;
318: dev_t condev;
319:
1.10 ! martin 320: /*
! 321: * Get console device, should either be ttyE0 or tty0n.
! 322: * Too hard to double check, so just 'know' the device numbers.
! 323: */
! 324: len = sizeof condev;
! 325: if (sysctl(conmib, __arraycount(conmib), &condev, &len, NULL, 0) != -1
! 326: && (condev & ~3) == 0x800) {
! 327: /* Motherboard serial port */
! 328: boottype.bp_consdev = (condev & 3) + 1;
! 329: /* Defaulting the baud rate to that of stdin should suffice */
! 330: if (tcgetattr(0, &t) != -1)
! 331: boottype.bp_conspeed = t.c_ispeed;
! 332:
1.9 martin 333: if (pm == NULL || !pm->no_part) {
334: /*
335: * Get console device, should either be ttyE0 or tty0n.
336: * Too hard to double check, so just 'know' the device numbers.
337: */
338: len = sizeof condev;
339: if (sysctl(conmib, nelem(conmib), &condev, &len, NULL, 0) != -1
340: && (condev & ~3) == 0x800) {
341: /* Motherboard serial port */
342: boottype.bp_consdev = (condev & 3) + 1;
343: /* Defaulting the baud rate to that of stdin should suffice */
344: if (tcgetattr(0, &t) != -1)
345: boottype.bp_conspeed = t.c_ispeed;
346: }
347:
348: process_menu(MENU_getboottype, &boottype);
349: msg_display(MSG_dobootblks, pm->diskdev);
350: if (boottype.bp_consdev == ~0u)
351: /* Use existing bootblocks */
352: return 0;
1.1 dholland 353: }
354:
355: ret = cp_to_target("/usr/mdec/boot", "/boot");
356: if (ret)
357: return ret;
1.9 martin 358: if (pm && pm->no_part)
359: return 0;
1.1 dholland 360:
1.9 martin 361: bootxx_filename = bootxx_name();
362: if (bootxx_filename != NULL) {
1.3 riz 363: snprintf(boot_options, sizeof boot_options,
364: "console=%s,speed=%u", consoles[boottype.bp_consdev],
365: boottype.bp_conspeed);
366: if (pm->isspecial) {
1.7 gson 367: ret = run_program(RUN_DISPLAY,
1.3 riz 368: "/usr/sbin/installboot -o %s /dev/r%s %s",
369: boot_options, pm->diskdev, bootxx_filename);
370: } else {
1.7 gson 371: ret = run_program(RUN_DISPLAY,
1.3 riz 372: "/usr/sbin/installboot -o %s /dev/r%s%c %s",
373: boot_options, pm->diskdev, 'a' + pm->rootpart,
374: bootxx_filename);
375: }
376: free(bootxx_filename);
377: } else
378: ret = -1;
379:
380: if (ret != 0)
381: process_menu(MENU_ok,
1.8 joerg 382: __UNCONST("Warning: disk is probably not bootable"));
1.1 dholland 383:
384: return ret;
385: }
386:
387: int
388: md_post_extract(void)
389: {
390: return 0;
391: }
392:
393: void
394: md_cleanup_install(void)
395: {
396: #ifndef DEBUG
397: enable_rc_conf();
398: add_rc_conf("wscons=YES\n");
399:
400: # if defined(__i386__) && defined(SET_KERNEL_TINY)
401: /*
402: * For GENERIC_TINY, do not enable any extra screens or wsmux.
403: * Otherwise, run getty on 4 VTs.
404: */
405: if (get_kernel_set() == SET_KERNEL_TINY)
406: run_program(RUN_CHROOT,
407: "sed -an -e '/^screen/s/^/#/;/^mux/s/^/#/;"
408: "H;$!d;g;w /etc/wscons.conf' /etc/wscons.conf");
409: else
410: # endif
411: run_program(RUN_CHROOT,
412: "sed -an -e '/^ttyE[1-9]/s/off/on/;"
413: "H;$!d;g;w /etc/ttys' /etc/ttys");
414:
415: #endif
416: }
417:
418: int
419: md_pre_update(void)
420: {
421: return 1;
422: }
423:
424: /* Upgrade support */
425: int
426: md_update(void)
427: {
428: md_post_newfs();
429: md_upgrade_mbrtype();
430: return 1;
431: }
432:
433: int
434: md_check_mbr(mbr_info_t *mbri)
435: {
436: return 2;
437: }
438:
439: int
440: md_mbr_use_wholedisk(mbr_info_t *mbri)
441: {
442: return mbr_use_wholedisk(mbri);
443: }
444:
445: static int
446: get_bios_info(char *dev)
447: {
448: static struct disklist *disklist = NULL;
449: static int mib[2] = {CTL_MACHDEP, CPU_DISKINFO};
450: int i;
451: size_t len;
452: struct biosdisk_info *bip;
453: struct nativedisk_info *nip = NULL, *nat;
454: int cyl, head;
455: daddr_t sec;
456:
457: if (disklist == NULL) {
458: if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0)
459: goto nogeom;
460: disklist = malloc(len);
461: if (disklist == NULL) {
462: fprintf(stderr, "Out of memory\n");
463: return -1;
464: }
465: sysctl(mib, 2, disklist, &len, NULL, 0);
466: }
467:
468: for (i = 0; i < disklist->dl_nnativedisks; i++) {
469: nat = &disklist->dl_nativedisks[i];
470: if (!strcmp(dev, nat->ni_devname)) {
471: nip = nat;
472: break;
473: }
474: }
475: if (nip == NULL || nip->ni_nmatches == 0) {
476: nogeom:
477: if (nip != NULL)
1.2 martin 478: msg_display(MSG_nobiosgeom, pm->dlcyl, pm->dlhead, pm->dlsec);
1.1 dholland 479: if (guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec) >= 0
480: && nip != NULL)
481: msg_display_add(MSG_biosguess, cyl, head, sec);
482: biosdisk = NULL;
483: } else {
484: guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec);
485: if (nip->ni_nmatches == 1) {
486: bip = &disklist->dl_biosdisks[nip->ni_biosmatches[0]];
487: msg_display(MSG_onebiosmatch);
488: msg_table_add(MSG_onebiosmatch_header);
489: msg_table_add(MSG_onebiosmatch_row, bip->bi_dev,
490: bip->bi_cyl, bip->bi_head, bip->bi_sec,
491: (unsigned)bip->bi_lbasecs,
492: (unsigned)(bip->bi_lbasecs / (1000000000 / 512)));
493: msg_display_add(MSG_biosgeom_advise);
494: biosdisk = bip;
495: process_menu(MENU_biosonematch, &biosdisk);
496: } else {
497: msg_display(MSG_biosmultmatch);
498: msg_table_add(MSG_biosmultmatch_header);
499: for (i = 0; i < nip->ni_nmatches; i++) {
500: bip = &disklist->dl_biosdisks[
501: nip->ni_biosmatches[i]];
502: msg_table_add(MSG_biosmultmatch_row, i,
503: bip->bi_dev, bip->bi_cyl, bip->bi_head,
504: bip->bi_sec, (unsigned)bip->bi_lbasecs,
505: (unsigned)bip->bi_lbasecs/(1000000000/512));
506: }
507: process_menu(MENU_biosmultmatch, &i);
508: if (i == -1)
509: biosdisk = NULL;
510: else
511: biosdisk = &disklist->dl_biosdisks[
512: nip->ni_biosmatches[i]];
513: }
514: }
515: if (biosdisk == NULL) {
516: if (nip != NULL) {
517: set_bios_geom(cyl, head, sec);
518: } else {
519: bcyl = cyl;
520: bhead = head;
521: bsec = sec;
522: }
523: } else {
524: bcyl = biosdisk->bi_cyl;
525: bhead = biosdisk->bi_head;
526: bsec = biosdisk->bi_sec;
527: }
528: return 0;
529: }
530:
531: static int
532: mbr_root_above_chs(void)
533: {
1.2 martin 534: return pm->ptstart + DEFROOTSIZE * (MEG / 512) >= bcyl * bhead * bsec;
1.1 dholland 535: }
536:
537: static void
538: md_upgrade_mbrtype(void)
539: {
540: struct mbr_partition *mbrp;
541: int i, netbsdpart = -1, oldbsdpart = -1, oldbsdcount = 0;
542:
1.2 martin 543: if (pm->no_mbr)
1.1 dholland 544: return;
545:
1.2 martin 546: if (read_mbr(pm->diskdev, &mbr) < 0)
1.1 dholland 547: return;
548:
549: mbrp = &mbr.mbr.mbr_parts[0];
550:
551: for (i = 0; i < MBR_PART_COUNT; i++) {
552: if (mbrp[i].mbrp_type == MBR_PTYPE_386BSD) {
553: oldbsdpart = i;
554: oldbsdcount++;
555: } else if (mbrp[i].mbrp_type == MBR_PTYPE_NETBSD)
556: netbsdpart = i;
557: }
558:
559: if (netbsdpart == -1 && oldbsdcount == 1) {
560: mbrp[oldbsdpart].mbrp_type = MBR_PTYPE_NETBSD;
1.2 martin 561: write_mbr(pm->diskdev, &mbr, 0);
1.1 dholland 562: }
563: }
564:
565: /*
566: * Read MBR code from a file.
567: * The existing partition table and bootselect configuration is kept.
568: */
569: static int
570: md_read_bootcode(const char *path, struct mbr_sector *mbrs)
571: {
572: int fd;
573: struct stat st;
574: size_t len;
575: struct mbr_sector new_mbr;
576: uint32_t dsn;
577:
578: fd = open(path, O_RDONLY);
579: if (fd < 0)
580: return -1;
581:
582: if (fstat(fd, &st) < 0 || st.st_size != sizeof *mbrs) {
583: close(fd);
584: return -1;
585: }
586:
587: if (read(fd, &new_mbr, sizeof new_mbr) != sizeof new_mbr) {
588: close(fd);
589: return -1;
590: }
591: close(fd);
592:
593: if (new_mbr.mbr_bootsel_magic != htole16(MBR_BS_MAGIC))
594: return -1;
595:
596: if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) {
597: len = offsetof(struct mbr_sector, mbr_bootsel);
598: } else
599: len = offsetof(struct mbr_sector, mbr_parts);
600:
601: /* Preserve the 'drive serial number' - especially for Vista */
602: dsn = mbrs->mbr_dsn;
603: memcpy(mbrs, &new_mbr, len);
604: mbrs->mbr_dsn = dsn;
605:
606: /* Keep flags from object file - indicate the properties */
607: mbrs->mbr_bootsel.mbrbs_flags = new_mbr.mbr_bootsel.mbrbs_flags;
608: mbrs->mbr_magic = htole16(MBR_MAGIC);
609:
610: return 0;
611: }
612:
613: static unsigned int
614: get_bootmodel(void)
615: {
616: #if defined(__i386__)
617: struct utsname ut;
618: #ifdef DEBUG
619: char *envstr;
620:
621: envstr = getenv("BOOTMODEL");
622: if (envstr != NULL)
623: return atoi(envstr);
624: #endif
625:
626: if (uname(&ut) < 0)
627: ut.version[0] = 0;
628:
629: #if defined(SET_KERNEL_TINY)
630: if (strstr(ut.version, "TINY") != NULL)
631: return SET_KERNEL_TINY;
632: #endif
633: #if defined(SET_KERNEL_PS2)
634: if (strstr(ut.version, "PS2") != NULL)
635: return SET_KERNEL_PS2;
636: #endif
637: #endif
638: return SET_KERNEL_GENERIC;
639: }
640:
641:
642: int
643: md_pre_mount()
644: {
645: return 0;
646: }
CVSweb <webmaster@jp.NetBSD.org>