16bc50445SMarcel Moolenaar /*- 2f6aa3fccSMarcel Moolenaar * Copyright (c) 2007, 2008 Marcel Moolenaar 36bc50445SMarcel Moolenaar * All rights reserved. 46bc50445SMarcel Moolenaar * 56bc50445SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 66bc50445SMarcel Moolenaar * modification, are permitted provided that the following conditions 76bc50445SMarcel Moolenaar * are met: 86bc50445SMarcel Moolenaar * 96bc50445SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 106bc50445SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 116bc50445SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 126bc50445SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 136bc50445SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 146bc50445SMarcel Moolenaar * 156bc50445SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 166bc50445SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 176bc50445SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 186bc50445SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 196bc50445SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 206bc50445SMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 216bc50445SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 226bc50445SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 236bc50445SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 246bc50445SMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 256bc50445SMarcel Moolenaar */ 266bc50445SMarcel Moolenaar 276bc50445SMarcel Moolenaar #include <sys/cdefs.h> 286bc50445SMarcel Moolenaar __FBSDID("$FreeBSD$"); 296bc50445SMarcel Moolenaar 306bc50445SMarcel Moolenaar #include <sys/param.h> 316bc50445SMarcel Moolenaar #include <sys/bio.h> 326bc50445SMarcel Moolenaar #include <sys/diskmbr.h> 336bc50445SMarcel Moolenaar #include <sys/endian.h> 346bc50445SMarcel Moolenaar #include <sys/kernel.h> 356bc50445SMarcel Moolenaar #include <sys/kobj.h> 366bc50445SMarcel Moolenaar #include <sys/limits.h> 376bc50445SMarcel Moolenaar #include <sys/lock.h> 386bc50445SMarcel Moolenaar #include <sys/malloc.h> 396bc50445SMarcel Moolenaar #include <sys/mutex.h> 406bc50445SMarcel Moolenaar #include <sys/queue.h> 416bc50445SMarcel Moolenaar #include <sys/sbuf.h> 426bc50445SMarcel Moolenaar #include <sys/systm.h> 436bc50445SMarcel Moolenaar #include <geom/geom.h> 446bc50445SMarcel Moolenaar #include <geom/part/g_part.h> 456bc50445SMarcel Moolenaar 466bc50445SMarcel Moolenaar #include "g_part_if.h" 476bc50445SMarcel Moolenaar 486bc50445SMarcel Moolenaar #define MBRSIZE 512 496bc50445SMarcel Moolenaar 506bc50445SMarcel Moolenaar struct g_part_mbr_table { 516bc50445SMarcel Moolenaar struct g_part_table base; 526bc50445SMarcel Moolenaar u_char mbr[MBRSIZE]; 536bc50445SMarcel Moolenaar }; 546bc50445SMarcel Moolenaar 556bc50445SMarcel Moolenaar struct g_part_mbr_entry { 566bc50445SMarcel Moolenaar struct g_part_entry base; 576bc50445SMarcel Moolenaar struct dos_partition ent; 586bc50445SMarcel Moolenaar }; 596bc50445SMarcel Moolenaar 606bc50445SMarcel Moolenaar static int g_part_mbr_add(struct g_part_table *, struct g_part_entry *, 616bc50445SMarcel Moolenaar struct g_part_parms *); 624d32fcb4SMarcel Moolenaar static int g_part_mbr_bootcode(struct g_part_table *, struct g_part_parms *); 636bc50445SMarcel Moolenaar static int g_part_mbr_create(struct g_part_table *, struct g_part_parms *); 646bc50445SMarcel Moolenaar static int g_part_mbr_destroy(struct g_part_table *, struct g_part_parms *); 65f4fddf53SWarner Losh static void g_part_mbr_dumpconf(struct g_part_table *, struct g_part_entry *, 665db67052SMarcel Moolenaar struct sbuf *, const char *); 676bc50445SMarcel Moolenaar static int g_part_mbr_dumpto(struct g_part_table *, struct g_part_entry *); 686bc50445SMarcel Moolenaar static int g_part_mbr_modify(struct g_part_table *, struct g_part_entry *, 696bc50445SMarcel Moolenaar struct g_part_parms *); 70f4fddf53SWarner Losh static const char *g_part_mbr_name(struct g_part_table *, struct g_part_entry *, 716bc50445SMarcel Moolenaar char *, size_t); 726bc50445SMarcel Moolenaar static int g_part_mbr_probe(struct g_part_table *, struct g_consumer *); 736bc50445SMarcel Moolenaar static int g_part_mbr_read(struct g_part_table *, struct g_consumer *); 74f6aa3fccSMarcel Moolenaar static int g_part_mbr_setunset(struct g_part_table *, struct g_part_entry *, 75f6aa3fccSMarcel Moolenaar const char *, unsigned int); 766bc50445SMarcel Moolenaar static const char *g_part_mbr_type(struct g_part_table *, struct g_part_entry *, 776bc50445SMarcel Moolenaar char *, size_t); 786bc50445SMarcel Moolenaar static int g_part_mbr_write(struct g_part_table *, struct g_consumer *); 793f71c319SMarcel Moolenaar static int g_part_mbr_resize(struct g_part_table *, struct g_part_entry *, 803f71c319SMarcel Moolenaar struct g_part_parms *); 816bc50445SMarcel Moolenaar 826bc50445SMarcel Moolenaar static kobj_method_t g_part_mbr_methods[] = { 836bc50445SMarcel Moolenaar KOBJMETHOD(g_part_add, g_part_mbr_add), 844d32fcb4SMarcel Moolenaar KOBJMETHOD(g_part_bootcode, g_part_mbr_bootcode), 856bc50445SMarcel Moolenaar KOBJMETHOD(g_part_create, g_part_mbr_create), 866bc50445SMarcel Moolenaar KOBJMETHOD(g_part_destroy, g_part_mbr_destroy), 875db67052SMarcel Moolenaar KOBJMETHOD(g_part_dumpconf, g_part_mbr_dumpconf), 886bc50445SMarcel Moolenaar KOBJMETHOD(g_part_dumpto, g_part_mbr_dumpto), 896bc50445SMarcel Moolenaar KOBJMETHOD(g_part_modify, g_part_mbr_modify), 903f71c319SMarcel Moolenaar KOBJMETHOD(g_part_resize, g_part_mbr_resize), 916bc50445SMarcel Moolenaar KOBJMETHOD(g_part_name, g_part_mbr_name), 926bc50445SMarcel Moolenaar KOBJMETHOD(g_part_probe, g_part_mbr_probe), 936bc50445SMarcel Moolenaar KOBJMETHOD(g_part_read, g_part_mbr_read), 94f6aa3fccSMarcel Moolenaar KOBJMETHOD(g_part_setunset, g_part_mbr_setunset), 956bc50445SMarcel Moolenaar KOBJMETHOD(g_part_type, g_part_mbr_type), 966bc50445SMarcel Moolenaar KOBJMETHOD(g_part_write, g_part_mbr_write), 976bc50445SMarcel Moolenaar { 0, 0 } 986bc50445SMarcel Moolenaar }; 996bc50445SMarcel Moolenaar 1006bc50445SMarcel Moolenaar static struct g_part_scheme g_part_mbr_scheme = { 1016bc50445SMarcel Moolenaar "MBR", 1026bc50445SMarcel Moolenaar g_part_mbr_methods, 1036bc50445SMarcel Moolenaar sizeof(struct g_part_mbr_table), 1046bc50445SMarcel Moolenaar .gps_entrysz = sizeof(struct g_part_mbr_entry), 1056bc50445SMarcel Moolenaar .gps_minent = NDOSPART, 1066bc50445SMarcel Moolenaar .gps_maxent = NDOSPART, 1074d32fcb4SMarcel Moolenaar .gps_bootcodesz = MBRSIZE, 1086bc50445SMarcel Moolenaar }; 1094ffca444SMarcel Moolenaar G_PART_SCHEME_DECLARE(g_part_mbr); 1106bc50445SMarcel Moolenaar 1116bc50445SMarcel Moolenaar static int 1126bc50445SMarcel Moolenaar mbr_parse_type(const char *type, u_char *dp_typ) 1136bc50445SMarcel Moolenaar { 1146bc50445SMarcel Moolenaar const char *alias; 1156bc50445SMarcel Moolenaar char *endp; 1166bc50445SMarcel Moolenaar long lt; 1176bc50445SMarcel Moolenaar 1186bc50445SMarcel Moolenaar if (type[0] == '!') { 1196bc50445SMarcel Moolenaar lt = strtol(type + 1, &endp, 0); 1206bc50445SMarcel Moolenaar if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256) 1216bc50445SMarcel Moolenaar return (EINVAL); 1226bc50445SMarcel Moolenaar *dp_typ = (u_char)lt; 1236bc50445SMarcel Moolenaar return (0); 1246bc50445SMarcel Moolenaar } 1256bc50445SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD); 1266bc50445SMarcel Moolenaar if (!strcasecmp(type, alias)) { 1276bc50445SMarcel Moolenaar *dp_typ = DOSPTYP_386BSD; 1286bc50445SMarcel Moolenaar return (0); 1296bc50445SMarcel Moolenaar } 130*c6b2b6fcSRui Paulo alias = g_part_alias_name(G_PART_ALIAS_MS_NTFS); 131*c6b2b6fcSRui Paulo if (!strcasecmp(type, alias)) { 132*c6b2b6fcSRui Paulo *dp_typ = DOSPTYP_NTFS; 133*c6b2b6fcSRui Paulo return (0); 134*c6b2b6fcSRui Paulo } 1356bc50445SMarcel Moolenaar return (EINVAL); 1366bc50445SMarcel Moolenaar } 1376bc50445SMarcel Moolenaar 138028de878SMarcel Moolenaar static int 139028de878SMarcel Moolenaar mbr_probe_bpb(u_char *bpb) 140028de878SMarcel Moolenaar { 141028de878SMarcel Moolenaar uint16_t secsz; 142028de878SMarcel Moolenaar uint8_t clstsz; 143028de878SMarcel Moolenaar 144028de878SMarcel Moolenaar #define PO2(x) ((x & (x - 1)) == 0) 145028de878SMarcel Moolenaar secsz = le16dec(bpb); 146028de878SMarcel Moolenaar if (secsz < 512 || secsz > 4096 || !PO2(secsz)) 147028de878SMarcel Moolenaar return (0); 148028de878SMarcel Moolenaar clstsz = bpb[2]; 149028de878SMarcel Moolenaar if (clstsz < 1 || clstsz > 128 || !PO2(clstsz)) 150028de878SMarcel Moolenaar return (0); 151028de878SMarcel Moolenaar #undef PO2 152028de878SMarcel Moolenaar 153028de878SMarcel Moolenaar return (1); 154028de878SMarcel Moolenaar } 155028de878SMarcel Moolenaar 1560081f96eSMarcel Moolenaar static void 1570081f96eSMarcel Moolenaar mbr_set_chs(struct g_part_table *table, uint32_t lba, u_char *cylp, u_char *hdp, 1580081f96eSMarcel Moolenaar u_char *secp) 1590081f96eSMarcel Moolenaar { 1600081f96eSMarcel Moolenaar uint32_t cyl, hd, sec; 1610081f96eSMarcel Moolenaar 1620081f96eSMarcel Moolenaar sec = lba % table->gpt_sectors + 1; 1630081f96eSMarcel Moolenaar lba /= table->gpt_sectors; 1640081f96eSMarcel Moolenaar hd = lba % table->gpt_heads; 1650081f96eSMarcel Moolenaar lba /= table->gpt_heads; 1660081f96eSMarcel Moolenaar cyl = lba; 1670081f96eSMarcel Moolenaar if (cyl > 1023) 1680081f96eSMarcel Moolenaar sec = hd = cyl = ~0; 1690081f96eSMarcel Moolenaar 1700081f96eSMarcel Moolenaar *cylp = cyl & 0xff; 1710081f96eSMarcel Moolenaar *hdp = hd & 0xff; 1720081f96eSMarcel Moolenaar *secp = (sec & 0x3f) | ((cyl >> 2) & 0xc0); 1730081f96eSMarcel Moolenaar } 1740081f96eSMarcel Moolenaar 1756bc50445SMarcel Moolenaar static int 1766bc50445SMarcel Moolenaar g_part_mbr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 1776bc50445SMarcel Moolenaar struct g_part_parms *gpp) 1786bc50445SMarcel Moolenaar { 1796bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 1806bc50445SMarcel Moolenaar struct g_part_mbr_table *table; 1810081f96eSMarcel Moolenaar uint32_t start, size, sectors; 1826bc50445SMarcel Moolenaar 1836bc50445SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) 1846bc50445SMarcel Moolenaar return (EINVAL); 1856bc50445SMarcel Moolenaar 1860081f96eSMarcel Moolenaar sectors = basetable->gpt_sectors; 1870081f96eSMarcel Moolenaar 1886bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 1896bc50445SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 1906bc50445SMarcel Moolenaar 1916bc50445SMarcel Moolenaar start = gpp->gpp_start; 1926bc50445SMarcel Moolenaar size = gpp->gpp_size; 1930081f96eSMarcel Moolenaar if (size < sectors) 1946bc50445SMarcel Moolenaar return (EINVAL); 1950081f96eSMarcel Moolenaar if (start % sectors) { 1960081f96eSMarcel Moolenaar size = size - sectors + (start % sectors); 1970081f96eSMarcel Moolenaar start = start - (start % sectors) + sectors; 1986bc50445SMarcel Moolenaar } 1990081f96eSMarcel Moolenaar if (size % sectors) 2000081f96eSMarcel Moolenaar size = size - (size % sectors); 2010081f96eSMarcel Moolenaar if (size < sectors) 2026bc50445SMarcel Moolenaar return (EINVAL); 2036bc50445SMarcel Moolenaar 2046bc50445SMarcel Moolenaar if (baseentry->gpe_deleted) 2056bc50445SMarcel Moolenaar bzero(&entry->ent, sizeof(entry->ent)); 2066bc50445SMarcel Moolenaar 2076bc50445SMarcel Moolenaar KASSERT(baseentry->gpe_start <= start, (__func__)); 2086bc50445SMarcel Moolenaar KASSERT(baseentry->gpe_end >= start + size - 1, (__func__)); 2096bc50445SMarcel Moolenaar baseentry->gpe_start = start; 2106bc50445SMarcel Moolenaar baseentry->gpe_end = start + size - 1; 2116bc50445SMarcel Moolenaar entry->ent.dp_start = start; 2126bc50445SMarcel Moolenaar entry->ent.dp_size = size; 2130081f96eSMarcel Moolenaar mbr_set_chs(basetable, baseentry->gpe_start, &entry->ent.dp_scyl, 2140081f96eSMarcel Moolenaar &entry->ent.dp_shd, &entry->ent.dp_ssect); 2150081f96eSMarcel Moolenaar mbr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, 2160081f96eSMarcel Moolenaar &entry->ent.dp_ehd, &entry->ent.dp_esect); 2176bc50445SMarcel Moolenaar return (mbr_parse_type(gpp->gpp_type, &entry->ent.dp_typ)); 2186bc50445SMarcel Moolenaar } 2196bc50445SMarcel Moolenaar 2206bc50445SMarcel Moolenaar static int 2214d32fcb4SMarcel Moolenaar g_part_mbr_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 2224d32fcb4SMarcel Moolenaar { 2234d32fcb4SMarcel Moolenaar struct g_part_mbr_table *table; 22466477112SMarcel Moolenaar size_t codesz; 2254d32fcb4SMarcel Moolenaar 22666477112SMarcel Moolenaar codesz = DOSPARTOFF; 2274d32fcb4SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 22866477112SMarcel Moolenaar bzero(table->mbr, codesz); 22966477112SMarcel Moolenaar codesz = MIN(codesz, gpp->gpp_codesize); 23066477112SMarcel Moolenaar if (codesz > 0) 23166477112SMarcel Moolenaar bcopy(gpp->gpp_codeptr, table->mbr, codesz); 2324d32fcb4SMarcel Moolenaar return (0); 2334d32fcb4SMarcel Moolenaar } 2344d32fcb4SMarcel Moolenaar 2354d32fcb4SMarcel Moolenaar static int 2366bc50445SMarcel Moolenaar g_part_mbr_create(struct g_part_table *basetable, struct g_part_parms *gpp) 2376bc50445SMarcel Moolenaar { 2386bc50445SMarcel Moolenaar struct g_consumer *cp; 2396bc50445SMarcel Moolenaar struct g_provider *pp; 2406bc50445SMarcel Moolenaar struct g_part_mbr_table *table; 2416154e492SMarcel Moolenaar uint32_t msize; 2426bc50445SMarcel Moolenaar 2436bc50445SMarcel Moolenaar pp = gpp->gpp_provider; 2446bc50445SMarcel Moolenaar cp = LIST_FIRST(&pp->consumers); 2456bc50445SMarcel Moolenaar 2460081f96eSMarcel Moolenaar if (pp->sectorsize < MBRSIZE) 2476bc50445SMarcel Moolenaar return (ENOSPC); 2486bc50445SMarcel Moolenaar 2496154e492SMarcel Moolenaar msize = MIN(pp->mediasize / pp->sectorsize, 0xffffffff); 2500081f96eSMarcel Moolenaar basetable->gpt_first = basetable->gpt_sectors; 2510081f96eSMarcel Moolenaar basetable->gpt_last = msize - (msize % basetable->gpt_sectors) - 1; 2526bc50445SMarcel Moolenaar 2536bc50445SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 2546bc50445SMarcel Moolenaar le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC); 2556bc50445SMarcel Moolenaar return (0); 2566bc50445SMarcel Moolenaar } 2576bc50445SMarcel Moolenaar 2586bc50445SMarcel Moolenaar static int 2596bc50445SMarcel Moolenaar g_part_mbr_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 2606bc50445SMarcel Moolenaar { 2616bc50445SMarcel Moolenaar 2626bc50445SMarcel Moolenaar /* Wipe the first sector to clear the partitioning. */ 2636bc50445SMarcel Moolenaar basetable->gpt_smhead |= 1; 2646bc50445SMarcel Moolenaar return (0); 2656bc50445SMarcel Moolenaar } 2666bc50445SMarcel Moolenaar 267f4fddf53SWarner Losh static void 2685db67052SMarcel Moolenaar g_part_mbr_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 2695db67052SMarcel Moolenaar struct sbuf *sb, const char *indent) 2705db67052SMarcel Moolenaar { 2715db67052SMarcel Moolenaar struct g_part_mbr_entry *entry; 2725db67052SMarcel Moolenaar 2735db67052SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 274a3354bb4SMarcel Moolenaar if (indent == NULL) { 275a3354bb4SMarcel Moolenaar /* conftxt: libdisk compatibility */ 2765db67052SMarcel Moolenaar sbuf_printf(sb, " xs MBR xt %u", entry->ent.dp_typ); 277a3354bb4SMarcel Moolenaar } else if (entry != NULL) { 278a3354bb4SMarcel Moolenaar /* confxml: partition entry information */ 279a3354bb4SMarcel Moolenaar sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 280a3354bb4SMarcel Moolenaar entry->ent.dp_typ); 281f6aa3fccSMarcel Moolenaar if (entry->ent.dp_flag & 0x80) 282f6aa3fccSMarcel Moolenaar sbuf_printf(sb, "%s<attrib>active</attrib>\n", indent); 283a3354bb4SMarcel Moolenaar } else { 284a3354bb4SMarcel Moolenaar /* confxml: scheme information */ 285a3354bb4SMarcel Moolenaar } 2865db67052SMarcel Moolenaar } 2875db67052SMarcel Moolenaar 2885db67052SMarcel Moolenaar static int 2896bc50445SMarcel Moolenaar g_part_mbr_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 2906bc50445SMarcel Moolenaar { 2916bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 2926bc50445SMarcel Moolenaar 2936bc50445SMarcel Moolenaar /* Allow dumping to a FreeBSD partition only. */ 2946bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 2956bc50445SMarcel Moolenaar return ((entry->ent.dp_typ == DOSPTYP_386BSD) ? 1 : 0); 2966bc50445SMarcel Moolenaar } 2976bc50445SMarcel Moolenaar 2986bc50445SMarcel Moolenaar static int 2996bc50445SMarcel Moolenaar g_part_mbr_modify(struct g_part_table *basetable, 3006bc50445SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 3016bc50445SMarcel Moolenaar { 3026bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 3036bc50445SMarcel Moolenaar 3046bc50445SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) 3056bc50445SMarcel Moolenaar return (EINVAL); 3066bc50445SMarcel Moolenaar 3076bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 3086bc50445SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_TYPE) 3096bc50445SMarcel Moolenaar return (mbr_parse_type(gpp->gpp_type, &entry->ent.dp_typ)); 3106bc50445SMarcel Moolenaar return (0); 3116bc50445SMarcel Moolenaar } 3126bc50445SMarcel Moolenaar 3133f71c319SMarcel Moolenaar static int 3143f71c319SMarcel Moolenaar g_part_mbr_resize(struct g_part_table *basetable, 3153f71c319SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 3163f71c319SMarcel Moolenaar { 3173f71c319SMarcel Moolenaar struct g_part_mbr_entry *entry; 3183f71c319SMarcel Moolenaar uint32_t size, sectors; 3193f71c319SMarcel Moolenaar 3203f71c319SMarcel Moolenaar sectors = basetable->gpt_sectors; 3213f71c319SMarcel Moolenaar size = gpp->gpp_size; 3223f71c319SMarcel Moolenaar 3233f71c319SMarcel Moolenaar if (size < sectors) 3243f71c319SMarcel Moolenaar return (EINVAL); 3253f71c319SMarcel Moolenaar if (size % sectors) 3263f71c319SMarcel Moolenaar size = size - (size % sectors); 3273f71c319SMarcel Moolenaar if (size < sectors) 3283f71c319SMarcel Moolenaar return (EINVAL); 3293f71c319SMarcel Moolenaar 3303f71c319SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 3313f71c319SMarcel Moolenaar baseentry->gpe_end = baseentry->gpe_start + size - 1; 3323f71c319SMarcel Moolenaar entry->ent.dp_size = size; 3333f71c319SMarcel Moolenaar mbr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, 3343f71c319SMarcel Moolenaar &entry->ent.dp_ehd, &entry->ent.dp_esect); 3353f71c319SMarcel Moolenaar return (0); 3363f71c319SMarcel Moolenaar } 3373f71c319SMarcel Moolenaar 338f4fddf53SWarner Losh static const char * 3396bc50445SMarcel Moolenaar g_part_mbr_name(struct g_part_table *table, struct g_part_entry *baseentry, 3406bc50445SMarcel Moolenaar char *buf, size_t bufsz) 3416bc50445SMarcel Moolenaar { 3426bc50445SMarcel Moolenaar 3436bc50445SMarcel Moolenaar snprintf(buf, bufsz, "s%d", baseentry->gpe_index); 3446bc50445SMarcel Moolenaar return (buf); 3456bc50445SMarcel Moolenaar } 3466bc50445SMarcel Moolenaar 3476bc50445SMarcel Moolenaar static int 3486bc50445SMarcel Moolenaar g_part_mbr_probe(struct g_part_table *table, struct g_consumer *cp) 3496bc50445SMarcel Moolenaar { 3505d68db5bSMarcel Moolenaar char psn[8]; 3516bc50445SMarcel Moolenaar struct g_provider *pp; 3526291ef2dSMarcel Moolenaar u_char *buf, *p; 353028de878SMarcel Moolenaar int error, index, res, sum; 3546291ef2dSMarcel Moolenaar uint16_t magic; 3556bc50445SMarcel Moolenaar 3566bc50445SMarcel Moolenaar pp = cp->provider; 3576bc50445SMarcel Moolenaar 3586bc50445SMarcel Moolenaar /* Sanity-check the provider. */ 3596bc50445SMarcel Moolenaar if (pp->sectorsize < MBRSIZE || pp->mediasize < pp->sectorsize) 3606bc50445SMarcel Moolenaar return (ENOSPC); 3616291ef2dSMarcel Moolenaar if (pp->sectorsize > 4096) 3626291ef2dSMarcel Moolenaar return (ENXIO); 3636bc50445SMarcel Moolenaar 3645d68db5bSMarcel Moolenaar /* We don't nest under an MBR (see EBR instead). */ 3655d68db5bSMarcel Moolenaar error = g_getattr("PART::scheme", cp, &psn); 3665d68db5bSMarcel Moolenaar if (error == 0 && strcmp(psn, g_part_mbr_scheme.name) == 0) 3675d68db5bSMarcel Moolenaar return (ELOOP); 3685d68db5bSMarcel Moolenaar 3696bc50445SMarcel Moolenaar /* Check that there's a MBR. */ 3706bc50445SMarcel Moolenaar buf = g_read_data(cp, 0L, pp->sectorsize, &error); 3716bc50445SMarcel Moolenaar if (buf == NULL) 3726bc50445SMarcel Moolenaar return (error); 3736291ef2dSMarcel Moolenaar 3746291ef2dSMarcel Moolenaar /* We goto out on mismatch. */ 3756291ef2dSMarcel Moolenaar res = ENXIO; 3766291ef2dSMarcel Moolenaar 3776291ef2dSMarcel Moolenaar magic = le16dec(buf + DOSMAGICOFFSET); 3786291ef2dSMarcel Moolenaar if (magic != DOSMAGIC) 3796291ef2dSMarcel Moolenaar goto out; 3806291ef2dSMarcel Moolenaar 3816291ef2dSMarcel Moolenaar for (index = 0; index < NDOSPART; index++) { 3826291ef2dSMarcel Moolenaar p = buf + DOSPARTOFF + index * DOSPARTSIZE; 3836291ef2dSMarcel Moolenaar if (p[0] != 0 && p[0] != 0x80) 3846291ef2dSMarcel Moolenaar goto out; 3856291ef2dSMarcel Moolenaar } 3866291ef2dSMarcel Moolenaar 387028de878SMarcel Moolenaar /* 388028de878SMarcel Moolenaar * If the partition table does not consist of all zeroes, 389028de878SMarcel Moolenaar * assume we have a MBR. If it's all zeroes, we could have 390028de878SMarcel Moolenaar * a boot sector. For example, a boot sector that doesn't 391028de878SMarcel Moolenaar * have boot code -- common on non-i386 hardware. In that 392028de878SMarcel Moolenaar * case we check if we have a possible BPB. If so, then we 393028de878SMarcel Moolenaar * assume we have a boot sector instead. 394028de878SMarcel Moolenaar */ 395028de878SMarcel Moolenaar sum = 0; 396028de878SMarcel Moolenaar for (index = 0; index < NDOSPART * DOSPARTSIZE; index++) 397028de878SMarcel Moolenaar sum += buf[DOSPARTOFF + index]; 398028de878SMarcel Moolenaar if (sum != 0 || !mbr_probe_bpb(buf + 0x0b)) 3996291ef2dSMarcel Moolenaar res = G_PART_PROBE_PRI_NORM; 4006291ef2dSMarcel Moolenaar 4016291ef2dSMarcel Moolenaar out: 4026bc50445SMarcel Moolenaar g_free(buf); 4036291ef2dSMarcel Moolenaar return (res); 4046bc50445SMarcel Moolenaar } 4056bc50445SMarcel Moolenaar 4066bc50445SMarcel Moolenaar static int 4076bc50445SMarcel Moolenaar g_part_mbr_read(struct g_part_table *basetable, struct g_consumer *cp) 4086bc50445SMarcel Moolenaar { 4096bc50445SMarcel Moolenaar struct dos_partition ent; 4106bc50445SMarcel Moolenaar struct g_provider *pp; 4116bc50445SMarcel Moolenaar struct g_part_mbr_table *table; 4126bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 4136bc50445SMarcel Moolenaar u_char *buf, *p; 4140081f96eSMarcel Moolenaar off_t chs, msize; 4150081f96eSMarcel Moolenaar u_int sectors, heads; 4160081f96eSMarcel Moolenaar int error, index; 4176bc50445SMarcel Moolenaar 4186bc50445SMarcel Moolenaar pp = cp->provider; 4196bc50445SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 4206bc50445SMarcel Moolenaar msize = pp->mediasize / pp->sectorsize; 4216bc50445SMarcel Moolenaar 4226bc50445SMarcel Moolenaar buf = g_read_data(cp, 0L, pp->sectorsize, &error); 4236bc50445SMarcel Moolenaar if (buf == NULL) 4246bc50445SMarcel Moolenaar return (error); 4256bc50445SMarcel Moolenaar 4266bc50445SMarcel Moolenaar bcopy(buf, table->mbr, sizeof(table->mbr)); 4276bc50445SMarcel Moolenaar for (index = NDOSPART - 1; index >= 0; index--) { 4286bc50445SMarcel Moolenaar p = buf + DOSPARTOFF + index * DOSPARTSIZE; 4296bc50445SMarcel Moolenaar ent.dp_flag = p[0]; 4306bc50445SMarcel Moolenaar ent.dp_shd = p[1]; 4316bc50445SMarcel Moolenaar ent.dp_ssect = p[2]; 4326bc50445SMarcel Moolenaar ent.dp_scyl = p[3]; 4336bc50445SMarcel Moolenaar ent.dp_typ = p[4]; 4346bc50445SMarcel Moolenaar ent.dp_ehd = p[5]; 4356bc50445SMarcel Moolenaar ent.dp_esect = p[6]; 4366bc50445SMarcel Moolenaar ent.dp_ecyl = p[7]; 4376bc50445SMarcel Moolenaar ent.dp_start = le32dec(p + 8); 4386bc50445SMarcel Moolenaar ent.dp_size = le32dec(p + 12); 4396bc50445SMarcel Moolenaar if (ent.dp_typ == 0 || ent.dp_typ == DOSPTYP_PMBR) 4406bc50445SMarcel Moolenaar continue; 4416bc50445SMarcel Moolenaar if (ent.dp_start == 0 || ent.dp_size == 0) 4426bc50445SMarcel Moolenaar continue; 4430081f96eSMarcel Moolenaar sectors = ent.dp_esect & 0x3f; 4440081f96eSMarcel Moolenaar if (sectors > basetable->gpt_sectors && 4450081f96eSMarcel Moolenaar !basetable->gpt_fixgeom) { 4460081f96eSMarcel Moolenaar g_part_geometry_heads(msize, sectors, &chs, &heads); 4470081f96eSMarcel Moolenaar if (chs != 0) { 4480081f96eSMarcel Moolenaar basetable->gpt_sectors = sectors; 4490081f96eSMarcel Moolenaar basetable->gpt_heads = heads; 4500081f96eSMarcel Moolenaar } 4510081f96eSMarcel Moolenaar } 4520081f96eSMarcel Moolenaar if ((ent.dp_start % basetable->gpt_sectors) != 0) 4536bc50445SMarcel Moolenaar printf("GEOM: %s: partition %d does not start on a " 4546bc50445SMarcel Moolenaar "track boundary.\n", pp->name, index + 1); 4550081f96eSMarcel Moolenaar if ((ent.dp_size % basetable->gpt_sectors) != 0) 4566bc50445SMarcel Moolenaar printf("GEOM: %s: partition %d does not end on a " 4576bc50445SMarcel Moolenaar "track boundary.\n", pp->name, index + 1); 4586bc50445SMarcel Moolenaar 4596bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)g_part_new_entry(basetable, 4606bc50445SMarcel Moolenaar index + 1, ent.dp_start, ent.dp_start + ent.dp_size - 1); 4616bc50445SMarcel Moolenaar entry->ent = ent; 4626bc50445SMarcel Moolenaar } 4630081f96eSMarcel Moolenaar 4640081f96eSMarcel Moolenaar basetable->gpt_entries = NDOSPART; 4650081f96eSMarcel Moolenaar basetable->gpt_first = basetable->gpt_sectors; 4660081f96eSMarcel Moolenaar basetable->gpt_last = msize - (msize % basetable->gpt_sectors) - 1; 4670081f96eSMarcel Moolenaar 4686bc50445SMarcel Moolenaar return (0); 4696bc50445SMarcel Moolenaar } 4706bc50445SMarcel Moolenaar 471f6aa3fccSMarcel Moolenaar static int 472f6aa3fccSMarcel Moolenaar g_part_mbr_setunset(struct g_part_table *table, struct g_part_entry *baseentry, 473f6aa3fccSMarcel Moolenaar const char *attrib, unsigned int set) 474f6aa3fccSMarcel Moolenaar { 475f6aa3fccSMarcel Moolenaar struct g_part_entry *iter; 476f6aa3fccSMarcel Moolenaar struct g_part_mbr_entry *entry; 477f6aa3fccSMarcel Moolenaar int changed; 478f6aa3fccSMarcel Moolenaar 479f6aa3fccSMarcel Moolenaar if (strcasecmp(attrib, "active") != 0) 480f6aa3fccSMarcel Moolenaar return (EINVAL); 481f6aa3fccSMarcel Moolenaar 482f6aa3fccSMarcel Moolenaar /* Only one entry can have the active attribute. */ 483f6aa3fccSMarcel Moolenaar LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) { 484f6aa3fccSMarcel Moolenaar if (iter->gpe_deleted) 485f6aa3fccSMarcel Moolenaar continue; 486f6aa3fccSMarcel Moolenaar changed = 0; 487f6aa3fccSMarcel Moolenaar entry = (struct g_part_mbr_entry *)iter; 488f6aa3fccSMarcel Moolenaar if (iter == baseentry) { 489f6aa3fccSMarcel Moolenaar if (set && (entry->ent.dp_flag & 0x80) == 0) { 490f6aa3fccSMarcel Moolenaar entry->ent.dp_flag |= 0x80; 491f6aa3fccSMarcel Moolenaar changed = 1; 492f6aa3fccSMarcel Moolenaar } else if (!set && (entry->ent.dp_flag & 0x80)) { 493f6aa3fccSMarcel Moolenaar entry->ent.dp_flag &= ~0x80; 494f6aa3fccSMarcel Moolenaar changed = 1; 495f6aa3fccSMarcel Moolenaar } 496f6aa3fccSMarcel Moolenaar } else { 497f6aa3fccSMarcel Moolenaar if (set && (entry->ent.dp_flag & 0x80)) { 498f6aa3fccSMarcel Moolenaar entry->ent.dp_flag &= ~0x80; 499f6aa3fccSMarcel Moolenaar changed = 1; 500f6aa3fccSMarcel Moolenaar } 501f6aa3fccSMarcel Moolenaar } 502f6aa3fccSMarcel Moolenaar if (changed && !iter->gpe_created) 503f6aa3fccSMarcel Moolenaar iter->gpe_modified = 1; 504f6aa3fccSMarcel Moolenaar } 505f6aa3fccSMarcel Moolenaar return (0); 506f6aa3fccSMarcel Moolenaar } 507f6aa3fccSMarcel Moolenaar 5086bc50445SMarcel Moolenaar static const char * 5096bc50445SMarcel Moolenaar g_part_mbr_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 5106bc50445SMarcel Moolenaar char *buf, size_t bufsz) 5116bc50445SMarcel Moolenaar { 5126bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 5136bc50445SMarcel Moolenaar int type; 5146bc50445SMarcel Moolenaar 5156bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 5166bc50445SMarcel Moolenaar type = entry->ent.dp_typ; 517*c6b2b6fcSRui Paulo switch (type) { 518*c6b2b6fcSRui Paulo case DOSPTYP_386BSD: 5196bc50445SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD)); 520*c6b2b6fcSRui Paulo case DOSPTYP_NTFS: 521*c6b2b6fcSRui Paulo return (g_part_alias_name(G_PART_ALIAS_MS_NTFS)); 522*c6b2b6fcSRui Paulo default: 5236bc50445SMarcel Moolenaar snprintf(buf, bufsz, "!%d", type); 524*c6b2b6fcSRui Paulo } 5256bc50445SMarcel Moolenaar return (buf); 5266bc50445SMarcel Moolenaar } 5276bc50445SMarcel Moolenaar 5286bc50445SMarcel Moolenaar static int 5296bc50445SMarcel Moolenaar g_part_mbr_write(struct g_part_table *basetable, struct g_consumer *cp) 5306bc50445SMarcel Moolenaar { 5316bc50445SMarcel Moolenaar struct g_part_entry *baseentry; 5326bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 5336bc50445SMarcel Moolenaar struct g_part_mbr_table *table; 5346bc50445SMarcel Moolenaar u_char *p; 5356bc50445SMarcel Moolenaar int error, index; 5366bc50445SMarcel Moolenaar 5376bc50445SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 5386bc50445SMarcel Moolenaar baseentry = LIST_FIRST(&basetable->gpt_entry); 5396bc50445SMarcel Moolenaar for (index = 1; index <= basetable->gpt_entries; index++) { 5406bc50445SMarcel Moolenaar p = table->mbr + DOSPARTOFF + (index - 1) * DOSPARTSIZE; 5416bc50445SMarcel Moolenaar entry = (baseentry != NULL && index == baseentry->gpe_index) 5426bc50445SMarcel Moolenaar ? (struct g_part_mbr_entry *)baseentry : NULL; 5436bc50445SMarcel Moolenaar if (entry != NULL && !baseentry->gpe_deleted) { 5446bc50445SMarcel Moolenaar p[0] = entry->ent.dp_flag; 5456bc50445SMarcel Moolenaar p[1] = entry->ent.dp_shd; 5466bc50445SMarcel Moolenaar p[2] = entry->ent.dp_ssect; 5476bc50445SMarcel Moolenaar p[3] = entry->ent.dp_scyl; 5486bc50445SMarcel Moolenaar p[4] = entry->ent.dp_typ; 5496bc50445SMarcel Moolenaar p[5] = entry->ent.dp_ehd; 5506bc50445SMarcel Moolenaar p[6] = entry->ent.dp_esect; 5516bc50445SMarcel Moolenaar p[7] = entry->ent.dp_ecyl; 5526bc50445SMarcel Moolenaar le32enc(p + 8, entry->ent.dp_start); 5536bc50445SMarcel Moolenaar le32enc(p + 12, entry->ent.dp_size); 5546bc50445SMarcel Moolenaar } else 5556bc50445SMarcel Moolenaar bzero(p, DOSPARTSIZE); 5566bc50445SMarcel Moolenaar 5576bc50445SMarcel Moolenaar if (entry != NULL) 5586bc50445SMarcel Moolenaar baseentry = LIST_NEXT(baseentry, gpe_entry); 5596bc50445SMarcel Moolenaar } 5606bc50445SMarcel Moolenaar 5616bc50445SMarcel Moolenaar error = g_write_data(cp, 0, table->mbr, cp->provider->sectorsize); 5626bc50445SMarcel Moolenaar return (error); 5636bc50445SMarcel Moolenaar } 564