The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/geom/part/g_part_mbr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2007, 2008 Marcel Moolenaar
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/8.0/sys/geom/part/g_part_mbr.c 190536 2009-03-30 00:53:46Z marcel $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/bio.h>
   32 #include <sys/diskmbr.h>
   33 #include <sys/endian.h>
   34 #include <sys/kernel.h>
   35 #include <sys/kobj.h>
   36 #include <sys/limits.h>
   37 #include <sys/lock.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mutex.h>
   40 #include <sys/queue.h>
   41 #include <sys/sbuf.h>
   42 #include <sys/systm.h>
   43 #include <geom/geom.h>
   44 #include <geom/part/g_part.h>
   45 
   46 #include "g_part_if.h"
   47 
   48 #define MBRSIZE         512
   49 
   50 struct g_part_mbr_table {
   51         struct g_part_table     base;
   52         u_char          mbr[MBRSIZE];
   53 };
   54 
   55 struct g_part_mbr_entry {
   56         struct g_part_entry     base;
   57         struct dos_partition ent;
   58 };
   59 
   60 static int g_part_mbr_add(struct g_part_table *, struct g_part_entry *,
   61     struct g_part_parms *);
   62 static int g_part_mbr_bootcode(struct g_part_table *, struct g_part_parms *);
   63 static int g_part_mbr_create(struct g_part_table *, struct g_part_parms *);
   64 static int g_part_mbr_destroy(struct g_part_table *, struct g_part_parms *);
   65 static void g_part_mbr_dumpconf(struct g_part_table *, struct g_part_entry *,
   66     struct sbuf *, const char *);
   67 static int g_part_mbr_dumpto(struct g_part_table *, struct g_part_entry *);
   68 static int g_part_mbr_modify(struct g_part_table *, struct g_part_entry *,  
   69     struct g_part_parms *);
   70 static const char *g_part_mbr_name(struct g_part_table *, struct g_part_entry *,
   71     char *, size_t);
   72 static int g_part_mbr_probe(struct g_part_table *, struct g_consumer *);
   73 static int g_part_mbr_read(struct g_part_table *, struct g_consumer *);
   74 static int g_part_mbr_setunset(struct g_part_table *, struct g_part_entry *,
   75     const char *, unsigned int);
   76 static const char *g_part_mbr_type(struct g_part_table *, struct g_part_entry *,
   77     char *, size_t);
   78 static int g_part_mbr_write(struct g_part_table *, struct g_consumer *);
   79 
   80 static kobj_method_t g_part_mbr_methods[] = {
   81         KOBJMETHOD(g_part_add,          g_part_mbr_add),
   82         KOBJMETHOD(g_part_bootcode,     g_part_mbr_bootcode),
   83         KOBJMETHOD(g_part_create,       g_part_mbr_create),
   84         KOBJMETHOD(g_part_destroy,      g_part_mbr_destroy),
   85         KOBJMETHOD(g_part_dumpconf,     g_part_mbr_dumpconf),
   86         KOBJMETHOD(g_part_dumpto,       g_part_mbr_dumpto),
   87         KOBJMETHOD(g_part_modify,       g_part_mbr_modify),
   88         KOBJMETHOD(g_part_name,         g_part_mbr_name),
   89         KOBJMETHOD(g_part_probe,        g_part_mbr_probe),
   90         KOBJMETHOD(g_part_read,         g_part_mbr_read),
   91         KOBJMETHOD(g_part_setunset,     g_part_mbr_setunset),
   92         KOBJMETHOD(g_part_type,         g_part_mbr_type),
   93         KOBJMETHOD(g_part_write,        g_part_mbr_write),
   94         { 0, 0 }
   95 };
   96 
   97 static struct g_part_scheme g_part_mbr_scheme = {
   98         "MBR",
   99         g_part_mbr_methods,
  100         sizeof(struct g_part_mbr_table),
  101         .gps_entrysz = sizeof(struct g_part_mbr_entry),
  102         .gps_minent = NDOSPART,
  103         .gps_maxent = NDOSPART,
  104         .gps_bootcodesz = MBRSIZE,
  105 };
  106 G_PART_SCHEME_DECLARE(g_part_mbr);
  107 
  108 static int
  109 mbr_parse_type(const char *type, u_char *dp_typ)
  110 {
  111         const char *alias;
  112         char *endp;
  113         long lt;
  114 
  115         if (type[0] == '!') {
  116                 lt = strtol(type + 1, &endp, 0);
  117                 if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256)
  118                         return (EINVAL);
  119                 *dp_typ = (u_char)lt;
  120                 return (0);
  121         }
  122         alias = g_part_alias_name(G_PART_ALIAS_FREEBSD);
  123         if (!strcasecmp(type, alias)) {
  124                 *dp_typ = DOSPTYP_386BSD;
  125                 return (0);
  126         }
  127         return (EINVAL);
  128 }
  129 
  130 static int
  131 mbr_probe_bpb(u_char *bpb)
  132 {
  133         uint16_t secsz;
  134         uint8_t clstsz;
  135 
  136 #define PO2(x)  ((x & (x - 1)) == 0)
  137         secsz = le16dec(bpb);
  138         if (secsz < 512 || secsz > 4096 || !PO2(secsz))
  139                 return (0);
  140         clstsz = bpb[2];
  141         if (clstsz < 1 || clstsz > 128 || !PO2(clstsz))
  142                 return (0);
  143 #undef PO2
  144 
  145         return (1);
  146 }
  147 
  148 static void
  149 mbr_set_chs(struct g_part_table *table, uint32_t lba, u_char *cylp, u_char *hdp,
  150     u_char *secp)
  151 {
  152         uint32_t cyl, hd, sec;
  153 
  154         sec = lba % table->gpt_sectors + 1;
  155         lba /= table->gpt_sectors;
  156         hd = lba % table->gpt_heads;
  157         lba /= table->gpt_heads;
  158         cyl = lba;
  159         if (cyl > 1023)
  160                 sec = hd = cyl = ~0;
  161 
  162         *cylp = cyl & 0xff;
  163         *hdp = hd & 0xff;
  164         *secp = (sec & 0x3f) | ((cyl >> 2) & 0xc0);
  165 }
  166 
  167 static int
  168 g_part_mbr_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
  169     struct g_part_parms *gpp)
  170 {
  171         struct g_part_mbr_entry *entry;
  172         struct g_part_mbr_table *table;
  173         uint32_t start, size, sectors;
  174 
  175         if (gpp->gpp_parms & G_PART_PARM_LABEL)
  176                 return (EINVAL);
  177 
  178         sectors = basetable->gpt_sectors;
  179 
  180         entry = (struct g_part_mbr_entry *)baseentry;
  181         table = (struct g_part_mbr_table *)basetable;
  182 
  183         start = gpp->gpp_start;
  184         size = gpp->gpp_size;
  185         if (size < sectors)
  186                 return (EINVAL);
  187         if (start % sectors) {
  188                 size = size - sectors + (start % sectors);
  189                 start = start - (start % sectors) + sectors;
  190         }
  191         if (size % sectors)
  192                 size = size - (size % sectors);
  193         if (size < sectors)
  194                 return (EINVAL);
  195 
  196         if (baseentry->gpe_deleted)
  197                 bzero(&entry->ent, sizeof(entry->ent));
  198 
  199         KASSERT(baseentry->gpe_start <= start, (__func__));
  200         KASSERT(baseentry->gpe_end >= start + size - 1, (__func__));
  201         baseentry->gpe_start = start;
  202         baseentry->gpe_end = start + size - 1;
  203         entry->ent.dp_start = start;
  204         entry->ent.dp_size = size;
  205         mbr_set_chs(basetable, baseentry->gpe_start, &entry->ent.dp_scyl,
  206             &entry->ent.dp_shd, &entry->ent.dp_ssect);
  207         mbr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl,
  208             &entry->ent.dp_ehd, &entry->ent.dp_esect);
  209         return (mbr_parse_type(gpp->gpp_type, &entry->ent.dp_typ));
  210 }
  211 
  212 static int
  213 g_part_mbr_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
  214 {
  215         struct g_part_mbr_table *table;
  216         size_t codesz;
  217 
  218         codesz = DOSPARTOFF;
  219         table = (struct g_part_mbr_table *)basetable;
  220         bzero(table->mbr, codesz);
  221         codesz = MIN(codesz,  gpp->gpp_codesize);
  222         if (codesz > 0)
  223                 bcopy(gpp->gpp_codeptr, table->mbr, codesz);
  224         return (0);
  225 }
  226 
  227 static int
  228 g_part_mbr_create(struct g_part_table *basetable, struct g_part_parms *gpp)
  229 {
  230         struct g_consumer *cp;
  231         struct g_provider *pp;
  232         struct g_part_mbr_table *table;
  233         uint32_t msize;
  234 
  235         pp = gpp->gpp_provider;
  236         cp = LIST_FIRST(&pp->consumers);
  237 
  238         if (pp->sectorsize < MBRSIZE)
  239                 return (ENOSPC);
  240 
  241         msize = MIN(pp->mediasize / pp->sectorsize, 0xffffffff);
  242         basetable->gpt_first = basetable->gpt_sectors;
  243         basetable->gpt_last = msize - (msize % basetable->gpt_sectors) - 1;
  244 
  245         table = (struct g_part_mbr_table *)basetable;
  246         le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC);
  247         return (0);
  248 }
  249 
  250 static int
  251 g_part_mbr_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
  252 {
  253 
  254         /* Wipe the first sector to clear the partitioning. */
  255         basetable->gpt_smhead |= 1;
  256         return (0);
  257 }
  258 
  259 static void
  260 g_part_mbr_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 
  261     struct sbuf *sb, const char *indent)
  262 {
  263         struct g_part_mbr_entry *entry;
  264  
  265         entry = (struct g_part_mbr_entry *)baseentry;
  266         if (indent == NULL) {
  267                 /* conftxt: libdisk compatibility */
  268                 sbuf_printf(sb, " xs MBR xt %u", entry->ent.dp_typ);
  269         } else if (entry != NULL) {
  270                 /* confxml: partition entry information */
  271                 sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent,
  272                     entry->ent.dp_typ);
  273                 if (entry->ent.dp_flag & 0x80)
  274                         sbuf_printf(sb, "%s<attrib>active</attrib>\n", indent);
  275         } else {
  276                 /* confxml: scheme information */
  277         }
  278 }
  279 
  280 static int
  281 g_part_mbr_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)  
  282 {
  283         struct g_part_mbr_entry *entry;
  284 
  285         /* Allow dumping to a FreeBSD partition only. */
  286         entry = (struct g_part_mbr_entry *)baseentry;
  287         return ((entry->ent.dp_typ == DOSPTYP_386BSD) ? 1 : 0);
  288 }
  289 
  290 static int
  291 g_part_mbr_modify(struct g_part_table *basetable,
  292     struct g_part_entry *baseentry, struct g_part_parms *gpp)
  293 {
  294         struct g_part_mbr_entry *entry;
  295 
  296         if (gpp->gpp_parms & G_PART_PARM_LABEL)
  297                 return (EINVAL);
  298 
  299         entry = (struct g_part_mbr_entry *)baseentry;
  300         if (gpp->gpp_parms & G_PART_PARM_TYPE)
  301                 return (mbr_parse_type(gpp->gpp_type, &entry->ent.dp_typ));
  302         return (0);
  303 }
  304 
  305 static const char *
  306 g_part_mbr_name(struct g_part_table *table, struct g_part_entry *baseentry,
  307     char *buf, size_t bufsz)
  308 {
  309 
  310         snprintf(buf, bufsz, "s%d", baseentry->gpe_index);
  311         return (buf);
  312 }
  313 
  314 static int
  315 g_part_mbr_probe(struct g_part_table *table, struct g_consumer *cp)
  316 {
  317         char psn[8];
  318         struct g_provider *pp;
  319         u_char *buf, *p;
  320         int error, index, res, sum;
  321         uint16_t magic;
  322 
  323         pp = cp->provider;
  324 
  325         /* Sanity-check the provider. */
  326         if (pp->sectorsize < MBRSIZE || pp->mediasize < pp->sectorsize)
  327                 return (ENOSPC);
  328         if (pp->sectorsize > 4096)
  329                 return (ENXIO);
  330 
  331         /* We don't nest under an MBR (see EBR instead). */
  332         error = g_getattr("PART::scheme", cp, &psn);
  333         if (error == 0 && strcmp(psn, g_part_mbr_scheme.name) == 0)
  334                 return (ELOOP);
  335 
  336         /* Check that there's a MBR. */
  337         buf = g_read_data(cp, 0L, pp->sectorsize, &error);
  338         if (buf == NULL)
  339                 return (error);
  340 
  341         /* We goto out on mismatch. */
  342         res = ENXIO;
  343 
  344         magic = le16dec(buf + DOSMAGICOFFSET);
  345         if (magic != DOSMAGIC)
  346                 goto out;
  347 
  348         for (index = 0; index < NDOSPART; index++) {
  349                 p = buf + DOSPARTOFF + index * DOSPARTSIZE;
  350                 if (p[0] != 0 && p[0] != 0x80)
  351                         goto out;
  352         }
  353 
  354         /*
  355          * If the partition table does not consist of all zeroes,
  356          * assume we have a MBR. If it's all zeroes, we could have
  357          * a boot sector. For example, a boot sector that doesn't
  358          * have boot code -- common on non-i386 hardware. In that
  359          * case we check if we have a possible BPB. If so, then we
  360          * assume we have a boot sector instead.
  361          */
  362         sum = 0;
  363         for (index = 0; index < NDOSPART * DOSPARTSIZE; index++)
  364                 sum += buf[DOSPARTOFF + index];
  365         if (sum != 0 || !mbr_probe_bpb(buf + 0x0b))
  366                 res = G_PART_PROBE_PRI_NORM;
  367 
  368  out:
  369         g_free(buf);
  370         return (res);
  371 }
  372 
  373 static int
  374 g_part_mbr_read(struct g_part_table *basetable, struct g_consumer *cp)
  375 {
  376         struct dos_partition ent;
  377         struct g_provider *pp;
  378         struct g_part_mbr_table *table;
  379         struct g_part_mbr_entry *entry;
  380         u_char *buf, *p;
  381         off_t chs, msize;
  382         u_int sectors, heads;
  383         int error, index;
  384 
  385         pp = cp->provider;
  386         table = (struct g_part_mbr_table *)basetable;
  387         msize = pp->mediasize / pp->sectorsize;
  388 
  389         buf = g_read_data(cp, 0L, pp->sectorsize, &error);
  390         if (buf == NULL)
  391                 return (error);
  392 
  393         bcopy(buf, table->mbr, sizeof(table->mbr));
  394         for (index = NDOSPART - 1; index >= 0; index--) {
  395                 p = buf + DOSPARTOFF + index * DOSPARTSIZE;
  396                 ent.dp_flag = p[0];
  397                 ent.dp_shd = p[1];
  398                 ent.dp_ssect = p[2];
  399                 ent.dp_scyl = p[3];
  400                 ent.dp_typ = p[4];
  401                 ent.dp_ehd = p[5];
  402                 ent.dp_esect = p[6];
  403                 ent.dp_ecyl = p[7];
  404                 ent.dp_start = le32dec(p + 8);
  405                 ent.dp_size = le32dec(p + 12);
  406                 if (ent.dp_typ == 0 || ent.dp_typ == DOSPTYP_PMBR)
  407                         continue;
  408                 if (ent.dp_start == 0 || ent.dp_size == 0)
  409                         continue;
  410                 sectors = ent.dp_esect & 0x3f;
  411                 if (sectors > basetable->gpt_sectors &&
  412                     !basetable->gpt_fixgeom) {
  413                         g_part_geometry_heads(msize, sectors, &chs, &heads);
  414                         if (chs != 0) {
  415                                 basetable->gpt_sectors = sectors;
  416                                 basetable->gpt_heads = heads;
  417                         }
  418                 }
  419                 if ((ent.dp_start % basetable->gpt_sectors) != 0)
  420                         printf("GEOM: %s: partition %d does not start on a "
  421                             "track boundary.\n", pp->name, index + 1);
  422                 if ((ent.dp_size % basetable->gpt_sectors) != 0)
  423                         printf("GEOM: %s: partition %d does not end on a "
  424                             "track boundary.\n", pp->name, index + 1);
  425 
  426                 entry = (struct g_part_mbr_entry *)g_part_new_entry(basetable,
  427                     index + 1, ent.dp_start, ent.dp_start + ent.dp_size - 1);
  428                 entry->ent = ent;
  429         }
  430 
  431         basetable->gpt_entries = NDOSPART;
  432         basetable->gpt_first = basetable->gpt_sectors;
  433         basetable->gpt_last = msize - (msize % basetable->gpt_sectors) - 1;
  434 
  435         return (0);
  436 }
  437 
  438 static int
  439 g_part_mbr_setunset(struct g_part_table *table, struct g_part_entry *baseentry,
  440     const char *attrib, unsigned int set)
  441 {
  442         struct g_part_entry *iter;
  443         struct g_part_mbr_entry *entry;
  444         int changed;
  445 
  446         if (strcasecmp(attrib, "active") != 0)
  447                 return (EINVAL);
  448 
  449         /* Only one entry can have the active attribute. */
  450         LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) {
  451                 if (iter->gpe_deleted)
  452                         continue;
  453                 changed = 0;
  454                 entry = (struct g_part_mbr_entry *)iter;
  455                 if (iter == baseentry) {
  456                         if (set && (entry->ent.dp_flag & 0x80) == 0) {
  457                                 entry->ent.dp_flag |= 0x80;
  458                                 changed = 1;
  459                         } else if (!set && (entry->ent.dp_flag & 0x80)) {
  460                                 entry->ent.dp_flag &= ~0x80;
  461                                 changed = 1;
  462                         }
  463                 } else {
  464                         if (set && (entry->ent.dp_flag & 0x80)) {
  465                                 entry->ent.dp_flag &= ~0x80;
  466                                 changed = 1;
  467                         }
  468                 }
  469                 if (changed && !iter->gpe_created)
  470                         iter->gpe_modified = 1;
  471         }
  472         return (0);
  473 }
  474 
  475 static const char *
  476 g_part_mbr_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 
  477     char *buf, size_t bufsz)
  478 {
  479         struct g_part_mbr_entry *entry;
  480         int type;
  481 
  482         entry = (struct g_part_mbr_entry *)baseentry;
  483         type = entry->ent.dp_typ;
  484         if (type == DOSPTYP_386BSD)
  485                 return (g_part_alias_name(G_PART_ALIAS_FREEBSD));
  486         snprintf(buf, bufsz, "!%d", type);
  487         return (buf);
  488 }
  489 
  490 static int
  491 g_part_mbr_write(struct g_part_table *basetable, struct g_consumer *cp)
  492 {
  493         struct g_part_entry *baseentry;
  494         struct g_part_mbr_entry *entry;
  495         struct g_part_mbr_table *table;
  496         u_char *p;
  497         int error, index;
  498 
  499         table = (struct g_part_mbr_table *)basetable;
  500         baseentry = LIST_FIRST(&basetable->gpt_entry);
  501         for (index = 1; index <= basetable->gpt_entries; index++) {
  502                 p = table->mbr + DOSPARTOFF + (index - 1) * DOSPARTSIZE;
  503                 entry = (baseentry != NULL && index == baseentry->gpe_index)
  504                     ? (struct g_part_mbr_entry *)baseentry : NULL;
  505                 if (entry != NULL && !baseentry->gpe_deleted) {
  506                         p[0] = entry->ent.dp_flag;
  507                         p[1] = entry->ent.dp_shd;
  508                         p[2] = entry->ent.dp_ssect;
  509                         p[3] = entry->ent.dp_scyl;
  510                         p[4] = entry->ent.dp_typ;
  511                         p[5] = entry->ent.dp_ehd;
  512                         p[6] = entry->ent.dp_esect;
  513                         p[7] = entry->ent.dp_ecyl;
  514                         le32enc(p + 8, entry->ent.dp_start);
  515                         le32enc(p + 12, entry->ent.dp_size);
  516                 } else
  517                         bzero(p, DOSPARTSIZE);
  518 
  519                 if (entry != NULL)
  520                         baseentry = LIST_NEXT(baseentry, gpe_entry);
  521         }
  522 
  523         error = g_write_data(cp, 0, table->mbr, cp->provider->sectorsize);
  524         return (error);
  525 }

Cache object: a18670ebb5edcfaf275199b5b138b61e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.