No empty .Rs/.Re
[netbsd-mini2440.git] / distrib / utils / sysinst / arch / i386 / md.c
blobc12aa383eb19727404650f09ef5153b01677a00a
1 /* $NetBSD: md.c,v 1.123 2009/09/19 14:57:28 abs Exp $ */
3 /*
4 * Copyright 1997 Piermont Information Systems Inc.
5 * All rights reserved.
7 * Based on code written by Philip A. Nelson for Piermont Information
8 * Systems Inc.
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. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed for the NetBSD Project by
21 * Piermont Information Systems Inc.
22 * 4. The name of Piermont Information Systems Inc. may not be used to endorse
23 * or promote products derived from this software without specific prior
24 * written permission.
26 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
36 * THE POSSIBILITY OF SUCH DAMAGE.
39 /* md.c -- i386 machine specific routines - also used by amd64 */
41 #include <sys/param.h>
42 #include <sys/sysctl.h>
43 #include <sys/exec.h>
44 #include <sys/utsname.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <machine/cpu.h>
48 #include <stdio.h>
49 #include <stddef.h>
50 #include <util.h>
51 #include <dirent.h>
53 #include "defs.h"
54 #include "md.h"
55 #include "endian.h"
56 #include "msg_defs.h"
57 #include "menu_defs.h"
59 #ifdef NO_LBA_READS /* for testing */
60 #undef BIFLAG_EXTINT13
61 #define BIFLAG_EXTINT13 0
62 #endif
64 static struct biosdisk_info *biosdisk = NULL;
66 /* prototypes */
68 static int get_bios_info(char *);
69 static int mbr_root_above_chs(void);
70 static void md_upgrade_mbrtype(void);
71 static int md_read_bootcode(const char *, struct mbr_sector *);
72 static unsigned int get_bootmodel(void);
74 void
75 md_init(void)
79 void
80 md_init_set_status(int minimal)
82 (void)minimal;
84 /* Default to install same type of kernel as we are running */
85 set_kernel_set(get_bootmodel());
88 int
89 md_get_info(void)
91 mbr_info_t *ext;
92 struct mbr_partition *p;
93 const char *bootcode;
94 int i;
95 int names, fl, ofl;
96 #define ACTIVE_FOUND 0x0100
97 #define NETBSD_ACTIVE 0x0200
98 #define NETBSD_NAMED 0x0400
99 #define ACTIVE_NAMED 0x0800
101 if (no_mbr)
102 return 1;
104 if (read_mbr(diskdev, &mbr) < 0)
105 memset(&mbr.mbr, 0, sizeof mbr.mbr - 2);
106 get_bios_info(diskdev);
108 edit:
109 if (edit_mbr(&mbr) == 0)
110 return 0;
112 root_limit = 0;
113 if (biosdisk != NULL && (biosdisk->bi_flags & BIFLAG_EXTINT13) == 0) {
114 if (mbr_root_above_chs()) {
115 msg_display(MSG_partabovechs);
116 process_menu(MENU_noyes, NULL);
117 if (!yesno)
118 goto edit;
119 /* The user is shooting themselves in the foot here...*/
120 } else
121 root_limit = bcyl * bhead * bsec;
125 * Ensure the install partition (at sector ptstart) and the active
126 * partition are bootable.
127 * Determine whether the bootselect code is needed.
128 * Note that MBR_BS_NEWMBR is always set, so we ignore it!
130 fl = 0;
131 names = 0;
132 for (ext = &mbr; ext != NULL; ext = ext->extended) {
133 p = ext->mbr.mbr_parts;
134 for (i = 0; i < MBR_PART_COUNT; p++, i++) {
135 if (p->mbrp_flag == MBR_PFLAG_ACTIVE) {
136 fl |= ACTIVE_FOUND;
137 if (ext->sector + p->mbrp_start == ptstart)
138 fl |= NETBSD_ACTIVE;
140 if (ext->mbrb.mbrbs_nametab[i][0] == 0) {
141 /* No bootmenu label... */
142 if (ext->sector == 0)
143 continue;
144 if (ext->sector + p->mbrp_start == ptstart)
146 * Have installed into an extended ptn
147 * force name & bootsel...
149 names++;
150 continue;
152 /* Partition has a bootmenu label... */
153 if (ext->sector != 0)
154 fl |= MBR_BS_EXTLBA;
155 if (ext->sector + p->mbrp_start == ptstart)
156 fl |= NETBSD_NAMED;
157 else if (p->mbrp_flag == MBR_PFLAG_ACTIVE)
158 fl |= ACTIVE_NAMED;
159 else
160 names++;
163 if (!(fl & ACTIVE_FOUND))
164 fl |= NETBSD_ACTIVE;
165 if (fl & NETBSD_NAMED && fl & NETBSD_ACTIVE)
166 fl |= ACTIVE_NAMED;
168 if ((names > 0 || !(fl & NETBSD_ACTIVE)) &&
169 (!(fl & NETBSD_NAMED) || !(fl & ACTIVE_NAMED))) {
171 * There appear to be multiple bootable partitions, but they
172 * don't all have bootmenu texts.
174 msg_display(MSG_missing_bootmenu_text);
175 process_menu(MENU_yesno, NULL);
176 if (yesno)
177 goto edit;
180 if ((fl & MBR_BS_EXTLBA) &&
181 (biosdisk == NULL || !(biosdisk->bi_flags & BIFLAG_EXTINT13))) {
182 /* Need unsupported LBA reads to read boot sectors */
183 msg_display(MSG_no_extended_bootmenu);
184 process_menu(MENU_noyes, NULL);
185 if (!yesno)
186 goto edit;
189 /* Sort out the name of the mbr code we need */
190 if (names > 0 || fl & (NETBSD_NAMED | ACTIVE_NAMED)) {
191 /* Need bootselect code */
192 fl |= MBR_BS_ACTIVE;
193 bootcode = fl & MBR_BS_EXTLBA ? _PATH_BOOTEXT : _PATH_BOOTSEL;
194 } else
195 bootcode = _PATH_MBR;
197 fl &= MBR_BS_ACTIVE | MBR_BS_EXTLBA;
199 /* Look at what is installed */
200 ofl = mbr.mbrb.mbrbs_flags;
201 if (ofl == 0) {
202 /* Check there is some bootcode at all... */
203 if (mbr.mbr.mbr_magic != htole16(MBR_MAGIC) ||
204 mbr.mbr.mbr_jmpboot[0] == 0 ||
205 mbr_root_above_chs())
206 /* Existing won't do, force update */
207 fl |= MBR_BS_NEWMBR;
209 ofl = mbr.oflags & (MBR_BS_ACTIVE | MBR_BS_EXTLBA);
211 if (fl & ~ofl || (fl == 0 && ofl & MBR_BS_ACTIVE)) {
212 /* Existing boot code isn't the right one... */
213 if (fl & MBR_BS_ACTIVE)
214 msg_display(MSG_installbootsel);
215 else
216 msg_display(MSG_installmbr);
217 } else
218 /* Existing code would (probably) be ok */
219 msg_display(MSG_updatembr);
221 process_menu(MENU_yesno, NULL);
222 if (!yesno)
223 /* User doesn't want to update mbr code */
224 return 1;
226 if (md_read_bootcode(bootcode, &mbr.mbr) == 0)
227 /* update suceeded - to memory copy */
228 return 1;
230 /* This shouldn't happen since the files are in the floppy fs... */
231 msg_display("Can't find %s", bootcode);
232 process_menu(MENU_yesno, NULL);
234 return 1;
238 * md back-end code for menu-driven BSD disklabel editor.
241 md_make_bsd_partitions(void)
243 return make_bsd_partitions();
247 * any additional partition validation
250 md_check_partitions(void)
252 int rval;
253 char *bootxx;
255 /* check we have boot code for the root partition type */
256 bootxx = bootxx_name();
257 rval = access(bootxx, R_OK);
258 free(bootxx);
259 if (rval == 0)
260 return 1;
261 process_menu(MENU_ok, deconst(MSG_No_Bootcode));
262 return 0;
266 * hook called before writing new disklabel.
269 md_pre_disklabel(void)
271 if (no_mbr)
272 return 0;
274 msg_display(MSG_dofdisk);
276 /* write edited MBR onto disk. */
277 if (write_mbr(diskdev, &mbr, 1) != 0) {
278 msg_display(MSG_wmbrfail);
279 process_menu(MENU_ok, NULL);
280 return 1;
282 return 0;
286 * hook called after writing disklabel to new target disk.
289 md_post_disklabel(void)
291 if (get_ramsize() <= 32)
292 set_swap(diskdev, bsdlabel);
294 return 0;
298 * hook called after upgrade() or install() has finished setting
299 * up the target disk but immediately before the user is given the
300 * ``disks are now set up'' message.
303 md_post_newfs(void)
305 int ret;
306 size_t len;
307 int td, sd;
308 char bootxx[8192 + 4];
309 char *bootxx_filename;
311 * XXX - should either find some way to pull this automatically
312 * from sys/arch/i386/stand/lib/boot_params.S, or just bite the
313 * bullet and include /sbin/installboot on the ramdisk
315 static struct x86_boot_params boottype =
316 {sizeof boottype, 0, 5, 0, 9600, { '\0' }, "", 0};
317 static int conmib[] = {CTL_MACHDEP, CPU_CONSDEV};
318 struct termios t;
319 dev_t condev;
320 #define bp (*(struct x86_boot_params *)(bootxx + 512 * 2 + 8))
323 * Get console device, should either be ttyE0 or tty0n.
324 * Too hard to double check, so just 'know' the device numbers.
326 len = sizeof condev;
327 if (sysctl(conmib, nelem(conmib), &condev, &len, NULL, 0) != -1
328 && (condev & ~3) == 0x800) {
329 /* Motherboard serial port */
330 boottype.bp_consdev = (condev & 3) + 1;
331 /* Defaulting the baud rate to that of stdin should suffice */
332 if (tcgetattr(0, &t) != -1)
333 boottype.bp_conspeed = t.c_ispeed;
336 process_menu(MENU_getboottype, &boottype);
337 msg_display(MSG_dobootblks, diskdev);
338 if (bp.bp_consdev == ~0u)
339 return 0;
341 ret = cp_to_target("/usr/mdec/boot", "/boot");
342 if (ret)
343 return ret;
345 /* Copy bootstrap in by hand - /sbin/installboot explodes ramdisks */
346 ret = 1;
348 snprintf(bootxx, sizeof bootxx, "/dev/r%s%c", diskdev, 'a' + rootpart);
349 td = open(bootxx, O_RDWR, 0);
350 bootxx_filename = bootxx_name();
351 if (bootxx_filename != NULL) {
352 sd = open(bootxx_filename, O_RDONLY);
353 free(bootxx_filename);
354 } else
355 sd = -1;
356 if (td == -1 || sd == -1)
357 goto bad_bootxx;
358 len = read(sd, bootxx, sizeof bootxx);
359 if (len < 2048 || len > 8192)
360 goto bad_bootxx;
362 if (*(uint32_t *)(bootxx + 512 * 2 + 4) != X86_BOOT_MAGIC_1)
363 goto bad_bootxx;
365 boottype.bp_length = bp.bp_length;
366 memcpy(&bp, &boottype, min(boottype.bp_length, sizeof boottype));
368 if (pwrite(td, bootxx, 512, 0) != 512)
369 goto bad_bootxx;
370 len -= 512 * 2;
371 if (pwrite(td, bootxx + 512 * 2, len, 2 * (off_t)512) - len != 0)
372 goto bad_bootxx;
373 ret = 0;
375 bad_bootxx:
376 close(td);
377 close(sd);
379 return ret;
383 md_post_extract(void)
385 return 0;
388 void
389 md_cleanup_install(void)
391 #ifndef DEBUG
392 enable_rc_conf();
393 add_rc_conf("wscons=YES\n");
395 # if defined(__i386__) && defined(SET_KERNEL_TINY)
397 * For GENERIC_TINY, do not enable any extra screens or wsmux.
398 * Otherwise, run getty on 4 VTs.
400 if (get_kernel_set() == SET_KERNEL_TINY)
401 run_program(RUN_CHROOT,
402 "sed -an -e '/^screen/s/^/#/;/^mux/s/^/#/;"
403 "H;$!d;g;w /etc/wscons.conf' /etc/wscons.conf");
404 else
405 # endif
406 run_program(RUN_CHROOT,
407 "sed -an -e '/^ttyE[1-9]/s/off/on/;"
408 "H;$!d;g;w /etc/ttys' /etc/ttys");
410 #endif
414 md_pre_update(void)
416 if (get_ramsize() <= 8)
417 set_swap(diskdev, NULL);
418 return 1;
421 /* Upgrade support */
423 md_update(void)
425 md_post_newfs();
426 md_upgrade_mbrtype();
427 return 1;
431 md_check_mbr(mbr_info_t *mbri)
433 return 2;
437 md_mbr_use_wholedisk(mbr_info_t *mbri)
439 return mbr_use_wholedisk(mbri);
442 static int
443 get_bios_info(char *dev)
445 static struct disklist *disklist = NULL;
446 static int mib[2] = {CTL_MACHDEP, CPU_DISKINFO};
447 int i;
448 size_t len;
449 struct biosdisk_info *bip;
450 struct nativedisk_info *nip = NULL, *nat;
451 int cyl, head;
452 daddr_t sec;
454 if (disklist == NULL) {
455 if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0)
456 goto nogeom;
457 disklist = malloc(len);
458 if (disklist == NULL) {
459 fprintf(stderr, "Out of memory\n");
460 return -1;
462 sysctl(mib, 2, disklist, &len, NULL, 0);
465 for (i = 0; i < disklist->dl_nnativedisks; i++) {
466 nat = &disklist->dl_nativedisks[i];
467 if (!strcmp(dev, nat->ni_devname)) {
468 nip = nat;
469 break;
472 if (nip == NULL || nip->ni_nmatches == 0) {
473 nogeom:
474 msg_display(MSG_nobiosgeom, dlcyl, dlhead, dlsec);
475 if (guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec) >= 0)
476 msg_display_add(MSG_biosguess, cyl, head, sec);
477 biosdisk = NULL;
478 } else {
479 guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec);
480 if (nip->ni_nmatches == 1) {
481 bip = &disklist->dl_biosdisks[nip->ni_biosmatches[0]];
482 msg_display(MSG_onebiosmatch);
483 msg_table_add(MSG_onebiosmatch_header);
484 msg_table_add(MSG_onebiosmatch_row, bip->bi_dev,
485 bip->bi_cyl, bip->bi_head, bip->bi_sec,
486 (unsigned)bip->bi_lbasecs,
487 (unsigned)(bip->bi_lbasecs / (1000000000 / 512)));
488 msg_display_add(MSG_biosgeom_advise);
489 biosdisk = bip;
490 process_menu(MENU_biosonematch, &biosdisk);
491 } else {
492 msg_display(MSG_biosmultmatch);
493 msg_table_add(MSG_biosmultmatch_header);
494 for (i = 0; i < nip->ni_nmatches; i++) {
495 bip = &disklist->dl_biosdisks[
496 nip->ni_biosmatches[i]];
497 msg_table_add(MSG_biosmultmatch_row, i,
498 bip->bi_dev, bip->bi_cyl, bip->bi_head,
499 bip->bi_sec, (unsigned)bip->bi_lbasecs,
500 (unsigned)bip->bi_lbasecs/(1000000000/512));
502 process_menu(MENU_biosmultmatch, &i);
503 if (i == -1)
504 biosdisk = NULL;
505 else
506 biosdisk = &disklist->dl_biosdisks[
507 nip->ni_biosmatches[i]];
510 if (biosdisk == NULL)
511 set_bios_geom(cyl, head, sec);
512 else {
513 bcyl = biosdisk->bi_cyl;
514 bhead = biosdisk->bi_head;
515 bsec = biosdisk->bi_sec;
517 return 0;
520 static int
521 mbr_root_above_chs(void)
523 return ptstart + DEFROOTSIZE * (MEG / 512) >= bcyl * bhead * bsec;
526 static void
527 md_upgrade_mbrtype(void)
529 struct mbr_partition *mbrp;
530 int i, netbsdpart = -1, oldbsdpart = -1, oldbsdcount = 0;
532 if (no_mbr)
533 return;
535 if (read_mbr(diskdev, &mbr) < 0)
536 return;
538 mbrp = &mbr.mbr.mbr_parts[0];
540 for (i = 0; i < MBR_PART_COUNT; i++) {
541 if (mbrp[i].mbrp_type == MBR_PTYPE_386BSD) {
542 oldbsdpart = i;
543 oldbsdcount++;
544 } else if (mbrp[i].mbrp_type == MBR_PTYPE_NETBSD)
545 netbsdpart = i;
548 if (netbsdpart == -1 && oldbsdcount == 1) {
549 mbrp[oldbsdpart].mbrp_type = MBR_PTYPE_NETBSD;
550 write_mbr(diskdev, &mbr, 0);
555 * Read MBR code from a file.
556 * The existing partition table and bootselect configuration is kept.
558 static int
559 md_read_bootcode(const char *path, struct mbr_sector *mbrs)
561 int fd;
562 struct stat st;
563 size_t len;
564 struct mbr_sector new_mbr;
565 uint32_t dsn;
567 fd = open(path, O_RDONLY);
568 if (fd < 0)
569 return -1;
571 if (fstat(fd, &st) < 0 || st.st_size != sizeof *mbrs) {
572 close(fd);
573 return -1;
576 if (read(fd, &new_mbr, sizeof new_mbr) != sizeof new_mbr) {
577 close(fd);
578 return -1;
580 close(fd);
582 if (new_mbr.mbr_bootsel_magic != htole16(MBR_BS_MAGIC))
583 return -1;
585 if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) {
586 len = offsetof(struct mbr_sector, mbr_bootsel);
587 } else
588 len = offsetof(struct mbr_sector, mbr_parts);
590 /* Preserve the 'drive serial number' - especially for Vista */
591 dsn = mbrs->mbr_dsn;
592 memcpy(mbrs, &new_mbr, len);
593 mbrs->mbr_dsn = dsn;
595 /* Keep flags from object file - indicate the properties */
596 mbrs->mbr_bootsel.mbrbs_flags = new_mbr.mbr_bootsel.mbrbs_flags;
597 mbrs->mbr_magic = htole16(MBR_MAGIC);
599 return 0;
602 static unsigned int
603 get_bootmodel(void)
605 #if defined(__i386__)
606 struct utsname ut;
607 #ifdef DEBUG
608 char *envstr;
610 envstr = getenv("BOOTMODEL");
611 if (envstr != NULL)
612 return atoi(envstr);
613 #endif
615 if (uname(&ut) < 0)
616 ut.version[0] = 0;
618 #if defined(SET_KERNEL_TINY)
619 if (strstr(ut.version, "TINY") != NULL)
620 return SET_KERNEL_TINY;
621 #endif
622 #if defined(SET_KERNEL_PS2)
623 if (strstr(ut.version, "PS2") != NULL)
624 return SET_KERNEL_PS2;
625 #endif
626 #endif
627 return SET_KERNEL_GENERIC;