[BACK]Return to md.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / sysinst / arch / i386

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/usr.sbin/sysinst/arch/i386/md.c between version 1.2.2.1 and 1.2.2.2

version 1.2.2.1, 2014/08/03 16:09:40 version 1.2.2.2, 2014/08/10 07:00:26
Line 0 
Line 1 
   /*      $NetBSD$ */
   
   /*
    * Copyright 1997 Piermont Information Systems Inc.
    * All rights reserved.
    *
    * Based on code written by Philip A. Nelson for Piermont Information
    * Systems Inc.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    * 1. Redistributions of source code must retain the above copyright
    *    notice, this list of conditions and the following disclaimer.
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in the
    *    documentation and/or other materials provided with the distribution.
    * 3. The name of Piermont Information Systems Inc. may not be used to endorse
    *    or promote products derived from this software without specific prior
    *    written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
    * THE POSSIBILITY OF SUCH DAMAGE.
    */
   
   /* md.c -- i386 machine specific routines - also used by amd64 */
   
   #include <sys/param.h>
   #include <sys/sysctl.h>
   #include <sys/exec.h>
   #include <sys/utsname.h>
   #include <sys/types.h>
   #include <sys/stat.h>
   #include <machine/cpu.h>
   #include <stdio.h>
   #include <stddef.h>
   #include <util.h>
   #include <dirent.h>
   #include <termios.h>
   
   #include "defs.h"
   #include "md.h"
   #include "endian.h"
   #include "msg_defs.h"
   #include "menu_defs.h"
   
   #ifdef NO_LBA_READS             /* for testing */
   #undef BIFLAG_EXTINT13
   #define BIFLAG_EXTINT13 0
   #endif
   
   static struct biosdisk_info *biosdisk = NULL;
   
   /* prototypes */
   
   static int get_bios_info(char *);
   static int mbr_root_above_chs(void);
   static void md_upgrade_mbrtype(void);
   static int md_read_bootcode(const char *, struct mbr_sector *);
   static unsigned int get_bootmodel(void);
   
   void
   md_init(void)
   {
   }
   
   void
   md_init_set_status(int flags)
   {
           (void)flags;
   
           /* Default to install same type of kernel as we are running */
           set_kernel_set(get_bootmodel());
   }
   
   int
   md_get_info(void)
   {
           mbr_info_t *ext;
           struct mbr_partition *p;
           const char *bootcode;
           int i;
           int names, fl, ofl;
   #define ACTIVE_FOUND    0x0100
   #define NETBSD_ACTIVE   0x0200
   #define NETBSD_NAMED    0x0400
   #define ACTIVE_NAMED    0x0800
   
           if (pm->no_mbr)
                   return 1;
   
           if (read_mbr(pm->diskdev, &mbr) < 0)
                   memset(&mbr.mbr, 0, sizeof mbr.mbr - 2);
           get_bios_info(pm->diskdev);
   
   edit:
           if (edit_mbr(&mbr) == 0)
                   return 0;
   
           root_limit = 0;
           if (biosdisk != NULL && (biosdisk->bi_flags & BIFLAG_EXTINT13) == 0) {
                   if (mbr_root_above_chs()) {
                           msg_display(MSG_partabovechs);
                           process_menu(MENU_noyes, NULL);
                           if (!yesno)
                                   goto edit;
                           /* The user is shooting themselves in the foot here...*/
                   } else
                           root_limit = bcyl * bhead * bsec;
           }
   
           /*
            * Ensure the install partition (at sector pm->ptstart) and the active
            * partition are bootable.
            * Determine whether the bootselect code is needed.
            * Note that MBR_BS_NEWMBR is always set, so we ignore it!
            */
           fl = 0;
           names = 0;
           for (ext = &mbr; ext != NULL; ext = ext->extended) {
                   p = ext->mbr.mbr_parts;
                   for (i = 0; i < MBR_PART_COUNT; p++, i++) {
                           if (p->mbrp_flag == MBR_PFLAG_ACTIVE) {
                                   fl |= ACTIVE_FOUND;
                               if (ext->sector + p->mbrp_start == pm->ptstart)
                                   fl |= NETBSD_ACTIVE;
                           }
                           if (ext->mbrb.mbrbs_nametab[i][0] == 0) {
                                   /* No bootmenu label... */
                                   if (ext->sector == 0)
                                           continue;
                                   if (ext->sector + p->mbrp_start == pm->ptstart)
                                           /*
                                            * Have installed into an extended ptn
                                            * force name & bootsel...
                                            */
                                           names++;
                                   continue;
                           }
                           /* Partition has a bootmenu label... */
                           if (ext->sector != 0)
                                   fl |= MBR_BS_EXTLBA;
                           if (ext->sector + p->mbrp_start == pm->ptstart)
                                   fl |= NETBSD_NAMED;
                           else if (p->mbrp_flag == MBR_PFLAG_ACTIVE)
                                   fl |= ACTIVE_NAMED;
                           else
                                   names++;
                   }
           }
           if (!(fl & ACTIVE_FOUND))
                   fl |= NETBSD_ACTIVE;
           if (fl & NETBSD_NAMED && fl & NETBSD_ACTIVE)
                   fl |= ACTIVE_NAMED;
   
           if ((names > 0 || !(fl & NETBSD_ACTIVE)) &&
               (!(fl & NETBSD_NAMED) || !(fl & ACTIVE_NAMED))) {
                   /*
                    * There appear to be multiple bootable partitions, but they
                    * don't all have bootmenu texts.
                    */
                   msg_display(MSG_missing_bootmenu_text);
                   process_menu(MENU_yesno, NULL);
                   if (yesno)
                           goto edit;
           }
   
           if ((fl & MBR_BS_EXTLBA) &&
               (biosdisk == NULL || !(biosdisk->bi_flags & BIFLAG_EXTINT13))) {
                   /* Need unsupported LBA reads to read boot sectors */
                   msg_display(MSG_no_extended_bootmenu);
                   process_menu(MENU_noyes, NULL);
                   if (!yesno)
                           goto edit;
           }
   
           /* Sort out the name of the mbr code we need */
           if (names > 0 || fl & (NETBSD_NAMED | ACTIVE_NAMED)) {
                   /* Need bootselect code */
                   fl |= MBR_BS_ACTIVE;
                   bootcode = fl & MBR_BS_EXTLBA ? _PATH_BOOTEXT : _PATH_BOOTSEL;
           } else
                   bootcode = _PATH_MBR;
   
           fl &=  MBR_BS_ACTIVE | MBR_BS_EXTLBA;
   
           /* Look at what is installed */
           ofl = mbr.mbrb.mbrbs_flags;
           if (ofl == 0) {
                   /* Check there is some bootcode at all... */
                   if (mbr.mbr.mbr_magic != htole16(MBR_MAGIC) ||
                       mbr.mbr.mbr_jmpboot[0] == 0 ||
                       mbr_root_above_chs())
                           /* Existing won't do, force update */
                           fl |= MBR_BS_NEWMBR;
           }
           ofl = mbr.oflags & (MBR_BS_ACTIVE | MBR_BS_EXTLBA);
   
           if (fl & ~ofl || (fl == 0 && ofl & MBR_BS_ACTIVE)) {
                   /* Existing boot code isn't the right one... */
                   if (fl & MBR_BS_ACTIVE)
                           msg_display(MSG_installbootsel);
                   else
                           msg_display(MSG_installmbr);
           } else
                   /* Existing code would (probably) be ok */
                   msg_display(MSG_updatembr);
   
           process_menu(MENU_yesno, NULL);
           if (!yesno)
                   /* User doesn't want to update mbr code */
                   return 1;
   
           if (md_read_bootcode(bootcode, &mbr.mbr) == 0)
                   /* update suceeded - to memory copy */
                   return 1;
   
           /* This shouldn't happen since the files are in the floppy fs... */
           msg_display("Can't find %s", bootcode);
           process_menu(MENU_yesno, NULL);
   
           return 1;
   }
   
   /*
    * md back-end code for menu-driven BSD disklabel editor.
    */
   int
   md_make_bsd_partitions(void)
   {
           return make_bsd_partitions();
   }
   
   /*
    * any additional partition validation
    */
   int
   md_check_partitions(void)
   {
           int rval;
           char *bootxx;
   
           /* check we have boot code for the root partition type */
           bootxx = bootxx_name();
           rval = access(bootxx, R_OK);
           free(bootxx);
           if (rval == 0)
                   return 1;
           process_menu(MENU_ok, deconst(MSG_No_Bootcode));
           return 0;
   }
   
   /*
    * hook called before writing new disklabel.
    */
   int
   md_pre_disklabel(void)
   {
           if (pm->no_mbr)
                   return 0;
   
           msg_display(MSG_dofdisk);
   
           /* write edited MBR onto disk. */
           if (write_mbr(pm->diskdev, &mbr, 1) != 0) {
                   msg_display(MSG_wmbrfail);
                   process_menu(MENU_ok, NULL);
                   return 1;
           }
           return 0;
   }
   
   /*
    * hook called after writing disklabel to new target disk.
    */
   int
   md_post_disklabel(void)
   {
           if (get_ramsize() <= 32)
                   set_swap(pm->diskdev, pm->bsdlabel);
   
           return 0;
   }
   
   /*
    * hook called after upgrade() or install() has finished setting
    * up the target disk but immediately before the user is given the
    * ``disks are now set up'' message.
    */
   int
   md_post_newfs(void)
   {
           int ret;
           size_t len;
           int td, sd;
           char bootxx[8192 + 4];
           char *bootxx_filename;
           /*
            * XXX - should either find some way to pull this automatically
            * from sys/arch/i386/stand/lib/boot_params.S, or just bite the
            * bullet and include /sbin/installboot on the ramdisk
            */
           static struct x86_boot_params boottype =
                   {sizeof boottype, 0, 5, 0, 9600, { '\0' }, "", 0};
           static int conmib[] = {CTL_MACHDEP, CPU_CONSDEV};
           struct termios t;
           dev_t condev;
   #define bp (*(struct x86_boot_params *)(bootxx + 512 * 2 + 8))
   
           /*
            * Get console device, should either be ttyE0 or tty0n.
            * Too hard to double check, so just 'know' the device numbers.
            */
           len = sizeof condev;
           if (sysctl(conmib, nelem(conmib), &condev, &len, NULL, 0) != -1
               && (condev & ~3) == 0x800) {
                   /* Motherboard serial port */
                   boottype.bp_consdev = (condev & 3) + 1;
                   /* Defaulting the baud rate to that of stdin should suffice */
                   if (tcgetattr(0, &t) != -1)
                           boottype.bp_conspeed = t.c_ispeed;
           }
   
           process_menu(MENU_getboottype, &boottype);
           msg_display(MSG_dobootblks, pm->diskdev);
           if (bp.bp_consdev == ~0u)
                   return 0;
   
           ret = cp_to_target("/usr/mdec/boot", "/boot");
           if (ret)
                   return ret;
   
           /* Copy bootstrap in by hand - /sbin/installboot explodes ramdisks */
           ret = 1;
   
           snprintf(bootxx, sizeof bootxx, "/dev/r%s%c", pm->diskdev, 'a' + pm->rootpart);
           td = open(bootxx, O_RDWR, 0);
           bootxx_filename = bootxx_name();
           if (bootxx_filename != NULL) {
                   sd = open(bootxx_filename, O_RDONLY);
                   free(bootxx_filename);
           } else
                   sd = -1;
           if (td == -1 || sd == -1)
                   goto bad_bootxx;
           len = read(sd, bootxx, sizeof bootxx);
           if (len < 2048 || len > 8192)
                   goto bad_bootxx;
   
           if (*(uint32_t *)(bootxx + 512 * 2 + 4) != X86_BOOT_MAGIC_1)
                   goto bad_bootxx;
   
           boottype.bp_length = bp.bp_length;
           memcpy(&bp, &boottype, min(boottype.bp_length, sizeof boottype));
   
           if (pwrite(td, bootxx, 512, 0) != 512)
                   goto bad_bootxx;
           len -= 512 * 2;
           if (pwrite(td, bootxx + 512 * 2, len, 2 * (off_t)512) - len != 0)
                   goto bad_bootxx;
           ret = 0;
   
       bad_bootxx:
           close(td);
           close(sd);
   
           return ret;
   }
   
   int
   md_post_extract(void)
   {
           return 0;
   }
   
   void
   md_cleanup_install(void)
   {
   #ifndef DEBUG
           enable_rc_conf();
           add_rc_conf("wscons=YES\n");
   
   # if defined(__i386__) && defined(SET_KERNEL_TINY)
           /*
            * For GENERIC_TINY, do not enable any extra screens or wsmux.
            * Otherwise, run getty on 4 VTs.
            */
           if (get_kernel_set() == SET_KERNEL_TINY)
                   run_program(RUN_CHROOT,
                               "sed -an -e '/^screen/s/^/#/;/^mux/s/^/#/;"
                               "H;$!d;g;w /etc/wscons.conf' /etc/wscons.conf");
           else
   # endif
                   run_program(RUN_CHROOT,
                               "sed -an -e '/^ttyE[1-9]/s/off/on/;"
                               "H;$!d;g;w /etc/ttys' /etc/ttys");
   
   #endif
   }
   
   int
   md_pre_update(void)
   {
           if (get_ramsize() <= 8)
                   set_swap(pm->diskdev, NULL);
           return 1;
   }
   
   /* Upgrade support */
   int
   md_update(void)
   {
           md_post_newfs();
           md_upgrade_mbrtype();
           return 1;
   }
   
   int
   md_check_mbr(mbr_info_t *mbri)
   {
           return 2;
   }
   
   int
   md_mbr_use_wholedisk(mbr_info_t *mbri)
   {
           return mbr_use_wholedisk(mbri);
   }
   
   static int
   get_bios_info(char *dev)
   {
           static struct disklist *disklist = NULL;
           static int mib[2] = {CTL_MACHDEP, CPU_DISKINFO};
           int i;
           size_t len;
           struct biosdisk_info *bip;
           struct nativedisk_info *nip = NULL, *nat;
           int cyl, head;
           daddr_t sec;
   
           if (disklist == NULL) {
                   if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0)
                           goto nogeom;
                   disklist = malloc(len);
                   if (disklist == NULL) {
                           fprintf(stderr, "Out of memory\n");
                           return -1;
                   }
                   sysctl(mib, 2, disklist, &len, NULL, 0);
           }
   
           for (i = 0; i < disklist->dl_nnativedisks; i++) {
                   nat = &disklist->dl_nativedisks[i];
                   if (!strcmp(dev, nat->ni_devname)) {
                           nip = nat;
                           break;
                   }
           }
           if (nip == NULL || nip->ni_nmatches == 0) {
   nogeom:
                   if (nip != NULL)
                           msg_display(MSG_nobiosgeom, pm->dlcyl, pm->dlhead, pm->dlsec);
                   if (guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec) >= 0
                       && nip != NULL)
                           msg_display_add(MSG_biosguess, cyl, head, sec);
                   biosdisk = NULL;
           } else {
                   guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec);
                   if (nip->ni_nmatches == 1) {
                           bip = &disklist->dl_biosdisks[nip->ni_biosmatches[0]];
                           msg_display(MSG_onebiosmatch);
                           msg_table_add(MSG_onebiosmatch_header);
                           msg_table_add(MSG_onebiosmatch_row, bip->bi_dev,
                               bip->bi_cyl, bip->bi_head, bip->bi_sec,
                               (unsigned)bip->bi_lbasecs,
                               (unsigned)(bip->bi_lbasecs / (1000000000 / 512)));
                           msg_display_add(MSG_biosgeom_advise);
                           biosdisk = bip;
                           process_menu(MENU_biosonematch, &biosdisk);
                   } else {
                           msg_display(MSG_biosmultmatch);
                           msg_table_add(MSG_biosmultmatch_header);
                           for (i = 0; i < nip->ni_nmatches; i++) {
                                   bip = &disklist->dl_biosdisks[
                                                           nip->ni_biosmatches[i]];
                                   msg_table_add(MSG_biosmultmatch_row, i,
                                       bip->bi_dev, bip->bi_cyl, bip->bi_head,
                                       bip->bi_sec, (unsigned)bip->bi_lbasecs,
                                       (unsigned)bip->bi_lbasecs/(1000000000/512));
                           }
                           process_menu(MENU_biosmultmatch, &i);
                           if (i == -1)
                                   biosdisk = NULL;
                           else
                                   biosdisk = &disklist->dl_biosdisks[
                                                           nip->ni_biosmatches[i]];
                   }
           }
           if (biosdisk == NULL) {
                   if (nip != NULL) {
                           set_bios_geom(cyl, head, sec);
                   } else {
                           bcyl = cyl;
                           bhead = head;
                           bsec = sec;
                   }
           } else {
                   bcyl = biosdisk->bi_cyl;
                   bhead = biosdisk->bi_head;
                   bsec = biosdisk->bi_sec;
           }
           return 0;
   }
   
   static int
   mbr_root_above_chs(void)
   {
           return pm->ptstart + DEFROOTSIZE * (MEG / 512) >= bcyl * bhead * bsec;
   }
   
   static void
   md_upgrade_mbrtype(void)
   {
           struct mbr_partition *mbrp;
           int i, netbsdpart = -1, oldbsdpart = -1, oldbsdcount = 0;
   
           if (pm->no_mbr)
                   return;
   
           if (read_mbr(pm->diskdev, &mbr) < 0)
                   return;
   
           mbrp = &mbr.mbr.mbr_parts[0];
   
           for (i = 0; i < MBR_PART_COUNT; i++) {
                   if (mbrp[i].mbrp_type == MBR_PTYPE_386BSD) {
                           oldbsdpart = i;
                           oldbsdcount++;
                   } else if (mbrp[i].mbrp_type == MBR_PTYPE_NETBSD)
                           netbsdpart = i;
           }
   
           if (netbsdpart == -1 && oldbsdcount == 1) {
                   mbrp[oldbsdpart].mbrp_type = MBR_PTYPE_NETBSD;
                   write_mbr(pm->diskdev, &mbr, 0);
           }
   }
   
   /*
    * Read MBR code from a file.
    * The existing partition table and bootselect configuration is kept.
    */
   static int
   md_read_bootcode(const char *path, struct mbr_sector *mbrs)
   {
           int fd;
           struct stat st;
           size_t len;
           struct mbr_sector new_mbr;
           uint32_t dsn;
   
           fd = open(path, O_RDONLY);
           if (fd < 0)
                   return -1;
   
           if (fstat(fd, &st) < 0 || st.st_size != sizeof *mbrs) {
                   close(fd);
                   return -1;
           }
   
           if (read(fd, &new_mbr, sizeof new_mbr) != sizeof new_mbr) {
                   close(fd);
                   return -1;
           }
           close(fd);
   
           if (new_mbr.mbr_bootsel_magic != htole16(MBR_BS_MAGIC))
                   return -1;
   
           if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) {
                   len = offsetof(struct mbr_sector, mbr_bootsel);
           } else
                   len = offsetof(struct mbr_sector, mbr_parts);
   
           /* Preserve the 'drive serial number' - especially for Vista */
           dsn = mbrs->mbr_dsn;
           memcpy(mbrs, &new_mbr, len);
           mbrs->mbr_dsn = dsn;
   
           /* Keep flags from object file - indicate the properties */
           mbrs->mbr_bootsel.mbrbs_flags = new_mbr.mbr_bootsel.mbrbs_flags;
           mbrs->mbr_magic = htole16(MBR_MAGIC);
   
           return 0;
   }
   
   static unsigned int
   get_bootmodel(void)
   {
   #if defined(__i386__)
           struct utsname ut;
   #ifdef DEBUG
           char *envstr;
   
           envstr = getenv("BOOTMODEL");
           if (envstr != NULL)
                   return atoi(envstr);
   #endif
   
           if (uname(&ut) < 0)
                   ut.version[0] = 0;
   
   #if defined(SET_KERNEL_TINY)
           if (strstr(ut.version, "TINY") != NULL)
                   return SET_KERNEL_TINY;
   #endif
   #if defined(SET_KERNEL_PS2)
           if (strstr(ut.version, "PS2") != NULL)
                   return SET_KERNEL_PS2;
   #endif
   #endif
           return SET_KERNEL_GENERIC;
   }
   
   
   int
   md_pre_mount()
   {
           return 0;
   }

Legend:
Removed from v.1.2.2.1  
changed lines
  Added in v.1.2.2.2

CVSweb <webmaster@jp.NetBSD.org>