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> 43cb08c2ccSAlexander Leidinger #include <sys/sysctl.h> 446bc50445SMarcel Moolenaar #include <geom/geom.h> 456bc50445SMarcel Moolenaar #include <geom/part/g_part.h> 466bc50445SMarcel Moolenaar 476bc50445SMarcel Moolenaar #include "g_part_if.h" 486bc50445SMarcel Moolenaar 49cb08c2ccSAlexander Leidinger FEATURE(geom_part_mbr, "GEOM partitioning class for MBR support"); 50cb08c2ccSAlexander Leidinger 516bc50445SMarcel Moolenaar #define MBRSIZE 512 526bc50445SMarcel Moolenaar 536bc50445SMarcel Moolenaar struct g_part_mbr_table { 546bc50445SMarcel Moolenaar struct g_part_table base; 556bc50445SMarcel Moolenaar u_char mbr[MBRSIZE]; 566bc50445SMarcel Moolenaar }; 576bc50445SMarcel Moolenaar 586bc50445SMarcel Moolenaar struct g_part_mbr_entry { 596bc50445SMarcel Moolenaar struct g_part_entry base; 606bc50445SMarcel Moolenaar struct dos_partition ent; 616bc50445SMarcel Moolenaar }; 626bc50445SMarcel Moolenaar 636bc50445SMarcel Moolenaar static int g_part_mbr_add(struct g_part_table *, struct g_part_entry *, 646bc50445SMarcel Moolenaar struct g_part_parms *); 654d32fcb4SMarcel Moolenaar static int g_part_mbr_bootcode(struct g_part_table *, struct g_part_parms *); 666bc50445SMarcel Moolenaar static int g_part_mbr_create(struct g_part_table *, struct g_part_parms *); 676bc50445SMarcel Moolenaar static int g_part_mbr_destroy(struct g_part_table *, struct g_part_parms *); 68f4fddf53SWarner Losh static void g_part_mbr_dumpconf(struct g_part_table *, struct g_part_entry *, 695db67052SMarcel Moolenaar struct sbuf *, const char *); 706bc50445SMarcel Moolenaar static int g_part_mbr_dumpto(struct g_part_table *, struct g_part_entry *); 716bc50445SMarcel Moolenaar static int g_part_mbr_modify(struct g_part_table *, struct g_part_entry *, 726bc50445SMarcel Moolenaar struct g_part_parms *); 73f4fddf53SWarner Losh static const char *g_part_mbr_name(struct g_part_table *, struct g_part_entry *, 746bc50445SMarcel Moolenaar char *, size_t); 756bc50445SMarcel Moolenaar static int g_part_mbr_probe(struct g_part_table *, struct g_consumer *); 766bc50445SMarcel Moolenaar static int g_part_mbr_read(struct g_part_table *, struct g_consumer *); 77f6aa3fccSMarcel Moolenaar static int g_part_mbr_setunset(struct g_part_table *, struct g_part_entry *, 78f6aa3fccSMarcel Moolenaar const char *, unsigned int); 796bc50445SMarcel Moolenaar static const char *g_part_mbr_type(struct g_part_table *, struct g_part_entry *, 806bc50445SMarcel Moolenaar char *, size_t); 816bc50445SMarcel Moolenaar static int g_part_mbr_write(struct g_part_table *, struct g_consumer *); 823f71c319SMarcel Moolenaar static int g_part_mbr_resize(struct g_part_table *, struct g_part_entry *, 833f71c319SMarcel Moolenaar struct g_part_parms *); 846bc50445SMarcel Moolenaar 856bc50445SMarcel Moolenaar static kobj_method_t g_part_mbr_methods[] = { 866bc50445SMarcel Moolenaar KOBJMETHOD(g_part_add, g_part_mbr_add), 874d32fcb4SMarcel Moolenaar KOBJMETHOD(g_part_bootcode, g_part_mbr_bootcode), 886bc50445SMarcel Moolenaar KOBJMETHOD(g_part_create, g_part_mbr_create), 896bc50445SMarcel Moolenaar KOBJMETHOD(g_part_destroy, g_part_mbr_destroy), 905db67052SMarcel Moolenaar KOBJMETHOD(g_part_dumpconf, g_part_mbr_dumpconf), 916bc50445SMarcel Moolenaar KOBJMETHOD(g_part_dumpto, g_part_mbr_dumpto), 926bc50445SMarcel Moolenaar KOBJMETHOD(g_part_modify, g_part_mbr_modify), 933f71c319SMarcel Moolenaar KOBJMETHOD(g_part_resize, g_part_mbr_resize), 946bc50445SMarcel Moolenaar KOBJMETHOD(g_part_name, g_part_mbr_name), 956bc50445SMarcel Moolenaar KOBJMETHOD(g_part_probe, g_part_mbr_probe), 966bc50445SMarcel Moolenaar KOBJMETHOD(g_part_read, g_part_mbr_read), 97f6aa3fccSMarcel Moolenaar KOBJMETHOD(g_part_setunset, g_part_mbr_setunset), 986bc50445SMarcel Moolenaar KOBJMETHOD(g_part_type, g_part_mbr_type), 996bc50445SMarcel Moolenaar KOBJMETHOD(g_part_write, g_part_mbr_write), 1006bc50445SMarcel Moolenaar { 0, 0 } 1016bc50445SMarcel Moolenaar }; 1026bc50445SMarcel Moolenaar 1036bc50445SMarcel Moolenaar static struct g_part_scheme g_part_mbr_scheme = { 1046bc50445SMarcel Moolenaar "MBR", 1056bc50445SMarcel Moolenaar g_part_mbr_methods, 1066bc50445SMarcel Moolenaar sizeof(struct g_part_mbr_table), 1076bc50445SMarcel Moolenaar .gps_entrysz = sizeof(struct g_part_mbr_entry), 1086bc50445SMarcel Moolenaar .gps_minent = NDOSPART, 1096bc50445SMarcel Moolenaar .gps_maxent = NDOSPART, 1104d32fcb4SMarcel Moolenaar .gps_bootcodesz = MBRSIZE, 1116bc50445SMarcel Moolenaar }; 1124ffca444SMarcel Moolenaar G_PART_SCHEME_DECLARE(g_part_mbr); 1136bc50445SMarcel Moolenaar 11488007f61SAndrey V. Elsukov static struct g_part_mbr_alias { 11588007f61SAndrey V. Elsukov u_char typ; 11688007f61SAndrey V. Elsukov int alias; 11788007f61SAndrey V. Elsukov } mbr_alias_match[] = { 11888007f61SAndrey V. Elsukov { DOSPTYP_386BSD, G_PART_ALIAS_FREEBSD }, 11988007f61SAndrey V. Elsukov { DOSPTYP_EXT, G_PART_ALIAS_EBR }, 12088007f61SAndrey V. Elsukov { DOSPTYP_NTFS, G_PART_ALIAS_MS_NTFS }, 12110f29053SGavin Atkinson { DOSPTYP_FAT16, G_PART_ALIAS_MS_FAT16 }, 12288007f61SAndrey V. Elsukov { DOSPTYP_FAT32, G_PART_ALIAS_MS_FAT32 }, 123c3f9f306SAndrey V. Elsukov { DOSPTYP_EXTLBA, G_PART_ALIAS_EBR }, 12448ef46e5SAndrey V. Elsukov { DOSPTYP_LDM, G_PART_ALIAS_MS_LDM_DATA }, 12588007f61SAndrey V. Elsukov { DOSPTYP_LINSWP, G_PART_ALIAS_LINUX_SWAP }, 12688007f61SAndrey V. Elsukov { DOSPTYP_LINUX, G_PART_ALIAS_LINUX_DATA }, 12788007f61SAndrey V. Elsukov { DOSPTYP_LINLVM, G_PART_ALIAS_LINUX_LVM }, 12888007f61SAndrey V. Elsukov { DOSPTYP_LINRAID, G_PART_ALIAS_LINUX_RAID }, 129090dd246SNathan Whitehorn { DOSPTYP_PPCBOOT, G_PART_ALIAS_FREEBSD_BOOT }, 130b20e4de3SDmitry Morozovsky { DOSPTYP_VMFS, G_PART_ALIAS_VMFS }, 131b20e4de3SDmitry Morozovsky { DOSPTYP_VMKDIAG, G_PART_ALIAS_VMKDIAG }, 13288007f61SAndrey V. Elsukov }; 13388007f61SAndrey V. Elsukov 1346bc50445SMarcel Moolenaar static int 1356bc50445SMarcel Moolenaar mbr_parse_type(const char *type, u_char *dp_typ) 1366bc50445SMarcel Moolenaar { 1376bc50445SMarcel Moolenaar const char *alias; 1386bc50445SMarcel Moolenaar char *endp; 1396bc50445SMarcel Moolenaar long lt; 14088007f61SAndrey V. Elsukov int i; 1416bc50445SMarcel Moolenaar 1426bc50445SMarcel Moolenaar if (type[0] == '!') { 1436bc50445SMarcel Moolenaar lt = strtol(type + 1, &endp, 0); 1446bc50445SMarcel Moolenaar if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256) 1456bc50445SMarcel Moolenaar return (EINVAL); 1466bc50445SMarcel Moolenaar *dp_typ = (u_char)lt; 1476bc50445SMarcel Moolenaar return (0); 1486bc50445SMarcel Moolenaar } 14988007f61SAndrey V. Elsukov for (i = 0; 15088007f61SAndrey V. Elsukov i < sizeof(mbr_alias_match) / sizeof(mbr_alias_match[0]); i++) { 15188007f61SAndrey V. Elsukov alias = g_part_alias_name(mbr_alias_match[i].alias); 15288007f61SAndrey V. Elsukov if (strcasecmp(type, alias) == 0) { 15388007f61SAndrey V. Elsukov *dp_typ = mbr_alias_match[i].typ; 1546bc50445SMarcel Moolenaar return (0); 1556bc50445SMarcel Moolenaar } 156c6b2b6fcSRui Paulo } 1576bc50445SMarcel Moolenaar return (EINVAL); 1586bc50445SMarcel Moolenaar } 1596bc50445SMarcel Moolenaar 160028de878SMarcel Moolenaar static int 161028de878SMarcel Moolenaar mbr_probe_bpb(u_char *bpb) 162028de878SMarcel Moolenaar { 163028de878SMarcel Moolenaar uint16_t secsz; 164028de878SMarcel Moolenaar uint8_t clstsz; 165028de878SMarcel Moolenaar 166028de878SMarcel Moolenaar #define PO2(x) ((x & (x - 1)) == 0) 167028de878SMarcel Moolenaar secsz = le16dec(bpb); 168028de878SMarcel Moolenaar if (secsz < 512 || secsz > 4096 || !PO2(secsz)) 169028de878SMarcel Moolenaar return (0); 170028de878SMarcel Moolenaar clstsz = bpb[2]; 171028de878SMarcel Moolenaar if (clstsz < 1 || clstsz > 128 || !PO2(clstsz)) 172028de878SMarcel Moolenaar return (0); 173028de878SMarcel Moolenaar #undef PO2 174028de878SMarcel Moolenaar 175028de878SMarcel Moolenaar return (1); 176028de878SMarcel Moolenaar } 177028de878SMarcel Moolenaar 1780081f96eSMarcel Moolenaar static void 1790081f96eSMarcel Moolenaar mbr_set_chs(struct g_part_table *table, uint32_t lba, u_char *cylp, u_char *hdp, 1800081f96eSMarcel Moolenaar u_char *secp) 1810081f96eSMarcel Moolenaar { 1820081f96eSMarcel Moolenaar uint32_t cyl, hd, sec; 1830081f96eSMarcel Moolenaar 1840081f96eSMarcel Moolenaar sec = lba % table->gpt_sectors + 1; 1850081f96eSMarcel Moolenaar lba /= table->gpt_sectors; 1860081f96eSMarcel Moolenaar hd = lba % table->gpt_heads; 1870081f96eSMarcel Moolenaar lba /= table->gpt_heads; 1880081f96eSMarcel Moolenaar cyl = lba; 1890081f96eSMarcel Moolenaar if (cyl > 1023) 1900081f96eSMarcel Moolenaar sec = hd = cyl = ~0; 1910081f96eSMarcel Moolenaar 1920081f96eSMarcel Moolenaar *cylp = cyl & 0xff; 1930081f96eSMarcel Moolenaar *hdp = hd & 0xff; 1940081f96eSMarcel Moolenaar *secp = (sec & 0x3f) | ((cyl >> 2) & 0xc0); 1950081f96eSMarcel Moolenaar } 1960081f96eSMarcel Moolenaar 1976bc50445SMarcel Moolenaar static int 198*bc1e8f56SAndrey V. Elsukov mbr_align(struct g_part_table *basetable, uint32_t *start, uint32_t *size) 199*bc1e8f56SAndrey V. Elsukov { 200*bc1e8f56SAndrey V. Elsukov uint32_t sectors; 201*bc1e8f56SAndrey V. Elsukov 202*bc1e8f56SAndrey V. Elsukov sectors = basetable->gpt_sectors; 203*bc1e8f56SAndrey V. Elsukov if (*size < sectors) 204*bc1e8f56SAndrey V. Elsukov return (EINVAL); 205*bc1e8f56SAndrey V. Elsukov if (start != NULL && (*start % sectors)) { 206*bc1e8f56SAndrey V. Elsukov *size += (*start % sectors) - sectors; 207*bc1e8f56SAndrey V. Elsukov *start -= (*start % sectors) - sectors; 208*bc1e8f56SAndrey V. Elsukov } 209*bc1e8f56SAndrey V. Elsukov if (*size % sectors) 210*bc1e8f56SAndrey V. Elsukov *size -= (*size % sectors); 211*bc1e8f56SAndrey V. Elsukov if (*size < sectors) 212*bc1e8f56SAndrey V. Elsukov return (EINVAL); 213*bc1e8f56SAndrey V. Elsukov return (0); 214*bc1e8f56SAndrey V. Elsukov } 215*bc1e8f56SAndrey V. Elsukov 216*bc1e8f56SAndrey V. Elsukov static int 2176bc50445SMarcel Moolenaar g_part_mbr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 2186bc50445SMarcel Moolenaar struct g_part_parms *gpp) 2196bc50445SMarcel Moolenaar { 2206bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 221*bc1e8f56SAndrey V. Elsukov uint32_t start, size; 2226bc50445SMarcel Moolenaar 2236bc50445SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) 2246bc50445SMarcel Moolenaar return (EINVAL); 2256bc50445SMarcel Moolenaar 2266bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 2276bc50445SMarcel Moolenaar start = gpp->gpp_start; 2286bc50445SMarcel Moolenaar size = gpp->gpp_size; 229*bc1e8f56SAndrey V. Elsukov if (mbr_align(basetable, &start, &size) != 0) 2306bc50445SMarcel Moolenaar return (EINVAL); 2316bc50445SMarcel Moolenaar if (baseentry->gpe_deleted) 2326bc50445SMarcel Moolenaar bzero(&entry->ent, sizeof(entry->ent)); 2336bc50445SMarcel Moolenaar 23442a783c1SRui Paulo KASSERT(baseentry->gpe_start <= start, ("%s", __func__)); 23542a783c1SRui Paulo KASSERT(baseentry->gpe_end >= start + size - 1, ("%s", __func__)); 2366bc50445SMarcel Moolenaar baseentry->gpe_start = start; 2376bc50445SMarcel Moolenaar baseentry->gpe_end = start + size - 1; 2386bc50445SMarcel Moolenaar entry->ent.dp_start = start; 2396bc50445SMarcel Moolenaar entry->ent.dp_size = size; 2400081f96eSMarcel Moolenaar mbr_set_chs(basetable, baseentry->gpe_start, &entry->ent.dp_scyl, 2410081f96eSMarcel Moolenaar &entry->ent.dp_shd, &entry->ent.dp_ssect); 2420081f96eSMarcel Moolenaar mbr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, 2430081f96eSMarcel Moolenaar &entry->ent.dp_ehd, &entry->ent.dp_esect); 2446bc50445SMarcel Moolenaar return (mbr_parse_type(gpp->gpp_type, &entry->ent.dp_typ)); 2456bc50445SMarcel Moolenaar } 2466bc50445SMarcel Moolenaar 2476bc50445SMarcel Moolenaar static int 2484d32fcb4SMarcel Moolenaar g_part_mbr_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 2494d32fcb4SMarcel Moolenaar { 2504d32fcb4SMarcel Moolenaar struct g_part_mbr_table *table; 25161162e85SAndrey V. Elsukov uint32_t dsn; 2524d32fcb4SMarcel Moolenaar 25361162e85SAndrey V. Elsukov if (gpp->gpp_codesize != MBRSIZE) 25461162e85SAndrey V. Elsukov return (ENODEV); 25561162e85SAndrey V. Elsukov 2564d32fcb4SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 25761162e85SAndrey V. Elsukov dsn = *(uint32_t *)(table->mbr + DOSDSNOFF); 25861162e85SAndrey V. Elsukov bcopy(gpp->gpp_codeptr, table->mbr, DOSPARTOFF); 25961162e85SAndrey V. Elsukov if (dsn != 0) 26061162e85SAndrey V. Elsukov *(uint32_t *)(table->mbr + DOSDSNOFF) = dsn; 2614d32fcb4SMarcel Moolenaar return (0); 2624d32fcb4SMarcel Moolenaar } 2634d32fcb4SMarcel Moolenaar 2644d32fcb4SMarcel Moolenaar static int 2656bc50445SMarcel Moolenaar g_part_mbr_create(struct g_part_table *basetable, struct g_part_parms *gpp) 2666bc50445SMarcel Moolenaar { 2676bc50445SMarcel Moolenaar struct g_provider *pp; 2686bc50445SMarcel Moolenaar struct g_part_mbr_table *table; 2696bc50445SMarcel Moolenaar 2706bc50445SMarcel Moolenaar pp = gpp->gpp_provider; 2710081f96eSMarcel Moolenaar if (pp->sectorsize < MBRSIZE) 2726bc50445SMarcel Moolenaar return (ENOSPC); 2736bc50445SMarcel Moolenaar 2740081f96eSMarcel Moolenaar basetable->gpt_first = basetable->gpt_sectors; 275db48d4a9SAndrey V. Elsukov basetable->gpt_last = MIN(pp->mediasize / pp->sectorsize, 276db48d4a9SAndrey V. Elsukov UINT32_MAX) - 1; 2776bc50445SMarcel Moolenaar 2786bc50445SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 2796bc50445SMarcel Moolenaar le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC); 2806bc50445SMarcel Moolenaar return (0); 2816bc50445SMarcel Moolenaar } 2826bc50445SMarcel Moolenaar 2836bc50445SMarcel Moolenaar static int 2846bc50445SMarcel Moolenaar g_part_mbr_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 2856bc50445SMarcel Moolenaar { 2866bc50445SMarcel Moolenaar 2876bc50445SMarcel Moolenaar /* Wipe the first sector to clear the partitioning. */ 2886bc50445SMarcel Moolenaar basetable->gpt_smhead |= 1; 2896bc50445SMarcel Moolenaar return (0); 2906bc50445SMarcel Moolenaar } 2916bc50445SMarcel Moolenaar 292f4fddf53SWarner Losh static void 2935db67052SMarcel Moolenaar g_part_mbr_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 2945db67052SMarcel Moolenaar struct sbuf *sb, const char *indent) 2955db67052SMarcel Moolenaar { 2965db67052SMarcel Moolenaar struct g_part_mbr_entry *entry; 2975db67052SMarcel Moolenaar 2985db67052SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 299a3354bb4SMarcel Moolenaar if (indent == NULL) { 300a3354bb4SMarcel Moolenaar /* conftxt: libdisk compatibility */ 3015db67052SMarcel Moolenaar sbuf_printf(sb, " xs MBR xt %u", entry->ent.dp_typ); 302a3354bb4SMarcel Moolenaar } else if (entry != NULL) { 303a3354bb4SMarcel Moolenaar /* confxml: partition entry information */ 304a3354bb4SMarcel Moolenaar sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 305a3354bb4SMarcel Moolenaar entry->ent.dp_typ); 306f6aa3fccSMarcel Moolenaar if (entry->ent.dp_flag & 0x80) 307f6aa3fccSMarcel Moolenaar sbuf_printf(sb, "%s<attrib>active</attrib>\n", indent); 308a3354bb4SMarcel Moolenaar } else { 309a3354bb4SMarcel Moolenaar /* confxml: scheme information */ 310a3354bb4SMarcel Moolenaar } 3115db67052SMarcel Moolenaar } 3125db67052SMarcel Moolenaar 3135db67052SMarcel Moolenaar static int 3146bc50445SMarcel Moolenaar g_part_mbr_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 3156bc50445SMarcel Moolenaar { 3166bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 3176bc50445SMarcel Moolenaar 318b5bad281SDon Lewis /* Allow dumping to a FreeBSD partition or Linux swap partition only. */ 3196bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 320b5bad281SDon Lewis return ((entry->ent.dp_typ == DOSPTYP_386BSD || 321b5bad281SDon Lewis entry->ent.dp_typ == DOSPTYP_LINSWP) ? 1 : 0); 3226bc50445SMarcel Moolenaar } 3236bc50445SMarcel Moolenaar 3246bc50445SMarcel Moolenaar static int 3256bc50445SMarcel Moolenaar g_part_mbr_modify(struct g_part_table *basetable, 3266bc50445SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 3276bc50445SMarcel Moolenaar { 3286bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 3296bc50445SMarcel Moolenaar 3306bc50445SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) 3316bc50445SMarcel Moolenaar return (EINVAL); 3326bc50445SMarcel Moolenaar 3336bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 3346bc50445SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_TYPE) 3356bc50445SMarcel Moolenaar return (mbr_parse_type(gpp->gpp_type, &entry->ent.dp_typ)); 3366bc50445SMarcel Moolenaar return (0); 3376bc50445SMarcel Moolenaar } 3386bc50445SMarcel Moolenaar 3393f71c319SMarcel Moolenaar static int 3403f71c319SMarcel Moolenaar g_part_mbr_resize(struct g_part_table *basetable, 3413f71c319SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 3423f71c319SMarcel Moolenaar { 3433f71c319SMarcel Moolenaar struct g_part_mbr_entry *entry; 344884c8e4fSAndrey V. Elsukov struct g_provider *pp; 345*bc1e8f56SAndrey V. Elsukov uint32_t size; 3463f71c319SMarcel Moolenaar 347884c8e4fSAndrey V. Elsukov if (baseentry == NULL) { 348884c8e4fSAndrey V. Elsukov pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 349884c8e4fSAndrey V. Elsukov basetable->gpt_last = MIN(pp->mediasize / pp->sectorsize, 350884c8e4fSAndrey V. Elsukov UINT32_MAX) - 1; 351884c8e4fSAndrey V. Elsukov return (0); 352884c8e4fSAndrey V. Elsukov } 3533f71c319SMarcel Moolenaar size = gpp->gpp_size; 354*bc1e8f56SAndrey V. Elsukov if (mbr_align(basetable, NULL, &size) != 0) 3553f71c319SMarcel Moolenaar return (EINVAL); 3563f71c319SMarcel Moolenaar 3573f71c319SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 3583f71c319SMarcel Moolenaar baseentry->gpe_end = baseentry->gpe_start + size - 1; 3593f71c319SMarcel Moolenaar entry->ent.dp_size = size; 3603f71c319SMarcel Moolenaar mbr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, 3613f71c319SMarcel Moolenaar &entry->ent.dp_ehd, &entry->ent.dp_esect); 3623f71c319SMarcel Moolenaar return (0); 3633f71c319SMarcel Moolenaar } 3643f71c319SMarcel Moolenaar 365f4fddf53SWarner Losh static const char * 3666bc50445SMarcel Moolenaar g_part_mbr_name(struct g_part_table *table, struct g_part_entry *baseentry, 3676bc50445SMarcel Moolenaar char *buf, size_t bufsz) 3686bc50445SMarcel Moolenaar { 3696bc50445SMarcel Moolenaar 3706bc50445SMarcel Moolenaar snprintf(buf, bufsz, "s%d", baseentry->gpe_index); 3716bc50445SMarcel Moolenaar return (buf); 3726bc50445SMarcel Moolenaar } 3736bc50445SMarcel Moolenaar 3746bc50445SMarcel Moolenaar static int 3756bc50445SMarcel Moolenaar g_part_mbr_probe(struct g_part_table *table, struct g_consumer *cp) 3766bc50445SMarcel Moolenaar { 3775d68db5bSMarcel Moolenaar char psn[8]; 3786bc50445SMarcel Moolenaar struct g_provider *pp; 3796291ef2dSMarcel Moolenaar u_char *buf, *p; 380028de878SMarcel Moolenaar int error, index, res, sum; 3816291ef2dSMarcel Moolenaar uint16_t magic; 3826bc50445SMarcel Moolenaar 3836bc50445SMarcel Moolenaar pp = cp->provider; 3846bc50445SMarcel Moolenaar 3856bc50445SMarcel Moolenaar /* Sanity-check the provider. */ 3866bc50445SMarcel Moolenaar if (pp->sectorsize < MBRSIZE || pp->mediasize < pp->sectorsize) 3876bc50445SMarcel Moolenaar return (ENOSPC); 3886291ef2dSMarcel Moolenaar if (pp->sectorsize > 4096) 3896291ef2dSMarcel Moolenaar return (ENXIO); 3906bc50445SMarcel Moolenaar 3915d68db5bSMarcel Moolenaar /* We don't nest under an MBR (see EBR instead). */ 3925d68db5bSMarcel Moolenaar error = g_getattr("PART::scheme", cp, &psn); 3935d68db5bSMarcel Moolenaar if (error == 0 && strcmp(psn, g_part_mbr_scheme.name) == 0) 3945d68db5bSMarcel Moolenaar return (ELOOP); 3955d68db5bSMarcel Moolenaar 3966bc50445SMarcel Moolenaar /* Check that there's a MBR. */ 3976bc50445SMarcel Moolenaar buf = g_read_data(cp, 0L, pp->sectorsize, &error); 3986bc50445SMarcel Moolenaar if (buf == NULL) 3996bc50445SMarcel Moolenaar return (error); 4006291ef2dSMarcel Moolenaar 4016291ef2dSMarcel Moolenaar /* We goto out on mismatch. */ 4026291ef2dSMarcel Moolenaar res = ENXIO; 4036291ef2dSMarcel Moolenaar 4046291ef2dSMarcel Moolenaar magic = le16dec(buf + DOSMAGICOFFSET); 4056291ef2dSMarcel Moolenaar if (magic != DOSMAGIC) 4066291ef2dSMarcel Moolenaar goto out; 4076291ef2dSMarcel Moolenaar 4086291ef2dSMarcel Moolenaar for (index = 0; index < NDOSPART; index++) { 4096291ef2dSMarcel Moolenaar p = buf + DOSPARTOFF + index * DOSPARTSIZE; 4106291ef2dSMarcel Moolenaar if (p[0] != 0 && p[0] != 0x80) 4116291ef2dSMarcel Moolenaar goto out; 4126291ef2dSMarcel Moolenaar } 4136291ef2dSMarcel Moolenaar 414028de878SMarcel Moolenaar /* 415028de878SMarcel Moolenaar * If the partition table does not consist of all zeroes, 416028de878SMarcel Moolenaar * assume we have a MBR. If it's all zeroes, we could have 417028de878SMarcel Moolenaar * a boot sector. For example, a boot sector that doesn't 418028de878SMarcel Moolenaar * have boot code -- common on non-i386 hardware. In that 419028de878SMarcel Moolenaar * case we check if we have a possible BPB. If so, then we 420028de878SMarcel Moolenaar * assume we have a boot sector instead. 421028de878SMarcel Moolenaar */ 422028de878SMarcel Moolenaar sum = 0; 423028de878SMarcel Moolenaar for (index = 0; index < NDOSPART * DOSPARTSIZE; index++) 424028de878SMarcel Moolenaar sum += buf[DOSPARTOFF + index]; 425028de878SMarcel Moolenaar if (sum != 0 || !mbr_probe_bpb(buf + 0x0b)) 4266291ef2dSMarcel Moolenaar res = G_PART_PROBE_PRI_NORM; 4276291ef2dSMarcel Moolenaar 4286291ef2dSMarcel Moolenaar out: 4296bc50445SMarcel Moolenaar g_free(buf); 4306291ef2dSMarcel Moolenaar return (res); 4316bc50445SMarcel Moolenaar } 4326bc50445SMarcel Moolenaar 4336bc50445SMarcel Moolenaar static int 4346bc50445SMarcel Moolenaar g_part_mbr_read(struct g_part_table *basetable, struct g_consumer *cp) 4356bc50445SMarcel Moolenaar { 4366bc50445SMarcel Moolenaar struct dos_partition ent; 4376bc50445SMarcel Moolenaar struct g_provider *pp; 4386bc50445SMarcel Moolenaar struct g_part_mbr_table *table; 4396bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 4406bc50445SMarcel Moolenaar u_char *buf, *p; 4419854b4eeSAndrey V. Elsukov off_t chs, msize, first; 4420081f96eSMarcel Moolenaar u_int sectors, heads; 4430081f96eSMarcel Moolenaar int error, index; 4446bc50445SMarcel Moolenaar 4456bc50445SMarcel Moolenaar pp = cp->provider; 4466bc50445SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 4479854b4eeSAndrey V. Elsukov first = basetable->gpt_sectors; 4484675b2b6SAndrey V. Elsukov msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); 4496bc50445SMarcel Moolenaar 4506bc50445SMarcel Moolenaar buf = g_read_data(cp, 0L, pp->sectorsize, &error); 4516bc50445SMarcel Moolenaar if (buf == NULL) 4526bc50445SMarcel Moolenaar return (error); 4536bc50445SMarcel Moolenaar 4546bc50445SMarcel Moolenaar bcopy(buf, table->mbr, sizeof(table->mbr)); 4556bc50445SMarcel Moolenaar for (index = NDOSPART - 1; index >= 0; index--) { 4566bc50445SMarcel Moolenaar p = buf + DOSPARTOFF + index * DOSPARTSIZE; 4576bc50445SMarcel Moolenaar ent.dp_flag = p[0]; 4586bc50445SMarcel Moolenaar ent.dp_shd = p[1]; 4596bc50445SMarcel Moolenaar ent.dp_ssect = p[2]; 4606bc50445SMarcel Moolenaar ent.dp_scyl = p[3]; 4616bc50445SMarcel Moolenaar ent.dp_typ = p[4]; 4626bc50445SMarcel Moolenaar ent.dp_ehd = p[5]; 4636bc50445SMarcel Moolenaar ent.dp_esect = p[6]; 4646bc50445SMarcel Moolenaar ent.dp_ecyl = p[7]; 4656bc50445SMarcel Moolenaar ent.dp_start = le32dec(p + 8); 4666bc50445SMarcel Moolenaar ent.dp_size = le32dec(p + 12); 4676bc50445SMarcel Moolenaar if (ent.dp_typ == 0 || ent.dp_typ == DOSPTYP_PMBR) 4686bc50445SMarcel Moolenaar continue; 4696bc50445SMarcel Moolenaar if (ent.dp_start == 0 || ent.dp_size == 0) 4706bc50445SMarcel Moolenaar continue; 4710081f96eSMarcel Moolenaar sectors = ent.dp_esect & 0x3f; 4720081f96eSMarcel Moolenaar if (sectors > basetable->gpt_sectors && 4730081f96eSMarcel Moolenaar !basetable->gpt_fixgeom) { 4740081f96eSMarcel Moolenaar g_part_geometry_heads(msize, sectors, &chs, &heads); 4750081f96eSMarcel Moolenaar if (chs != 0) { 4760081f96eSMarcel Moolenaar basetable->gpt_sectors = sectors; 4770081f96eSMarcel Moolenaar basetable->gpt_heads = heads; 4780081f96eSMarcel Moolenaar } 4790081f96eSMarcel Moolenaar } 4809854b4eeSAndrey V. Elsukov if (ent.dp_start < first) 4819854b4eeSAndrey V. Elsukov first = ent.dp_start; 4826bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)g_part_new_entry(basetable, 4836bc50445SMarcel Moolenaar index + 1, ent.dp_start, ent.dp_start + ent.dp_size - 1); 4846bc50445SMarcel Moolenaar entry->ent = ent; 4856bc50445SMarcel Moolenaar } 4860081f96eSMarcel Moolenaar 4870081f96eSMarcel Moolenaar basetable->gpt_entries = NDOSPART; 4880081f96eSMarcel Moolenaar basetable->gpt_first = basetable->gpt_sectors; 489db48d4a9SAndrey V. Elsukov basetable->gpt_last = msize - 1; 4900081f96eSMarcel Moolenaar 4919854b4eeSAndrey V. Elsukov if (first < basetable->gpt_first) 4929854b4eeSAndrey V. Elsukov basetable->gpt_first = 1; 4939854b4eeSAndrey V. Elsukov 494b1da166eSAndrey V. Elsukov g_free(buf); 4956bc50445SMarcel Moolenaar return (0); 4966bc50445SMarcel Moolenaar } 4976bc50445SMarcel Moolenaar 498f6aa3fccSMarcel Moolenaar static int 499f6aa3fccSMarcel Moolenaar g_part_mbr_setunset(struct g_part_table *table, struct g_part_entry *baseentry, 500f6aa3fccSMarcel Moolenaar const char *attrib, unsigned int set) 501f6aa3fccSMarcel Moolenaar { 502f6aa3fccSMarcel Moolenaar struct g_part_entry *iter; 503f6aa3fccSMarcel Moolenaar struct g_part_mbr_entry *entry; 504f6aa3fccSMarcel Moolenaar int changed; 505f6aa3fccSMarcel Moolenaar 5063bd22a9cSMarcel Moolenaar if (baseentry == NULL) 5073bd22a9cSMarcel Moolenaar return (ENODEV); 508f6aa3fccSMarcel Moolenaar if (strcasecmp(attrib, "active") != 0) 509f6aa3fccSMarcel Moolenaar return (EINVAL); 510f6aa3fccSMarcel Moolenaar 511f6aa3fccSMarcel Moolenaar /* Only one entry can have the active attribute. */ 512f6aa3fccSMarcel Moolenaar LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) { 513f6aa3fccSMarcel Moolenaar if (iter->gpe_deleted) 514f6aa3fccSMarcel Moolenaar continue; 515f6aa3fccSMarcel Moolenaar changed = 0; 516f6aa3fccSMarcel Moolenaar entry = (struct g_part_mbr_entry *)iter; 517f6aa3fccSMarcel Moolenaar if (iter == baseentry) { 518f6aa3fccSMarcel Moolenaar if (set && (entry->ent.dp_flag & 0x80) == 0) { 519f6aa3fccSMarcel Moolenaar entry->ent.dp_flag |= 0x80; 520f6aa3fccSMarcel Moolenaar changed = 1; 521f6aa3fccSMarcel Moolenaar } else if (!set && (entry->ent.dp_flag & 0x80)) { 522f6aa3fccSMarcel Moolenaar entry->ent.dp_flag &= ~0x80; 523f6aa3fccSMarcel Moolenaar changed = 1; 524f6aa3fccSMarcel Moolenaar } 525f6aa3fccSMarcel Moolenaar } else { 526f6aa3fccSMarcel Moolenaar if (set && (entry->ent.dp_flag & 0x80)) { 527f6aa3fccSMarcel Moolenaar entry->ent.dp_flag &= ~0x80; 528f6aa3fccSMarcel Moolenaar changed = 1; 529f6aa3fccSMarcel Moolenaar } 530f6aa3fccSMarcel Moolenaar } 531f6aa3fccSMarcel Moolenaar if (changed && !iter->gpe_created) 532f6aa3fccSMarcel Moolenaar iter->gpe_modified = 1; 533f6aa3fccSMarcel Moolenaar } 534f6aa3fccSMarcel Moolenaar return (0); 535f6aa3fccSMarcel Moolenaar } 536f6aa3fccSMarcel Moolenaar 5376bc50445SMarcel Moolenaar static const char * 5386bc50445SMarcel Moolenaar g_part_mbr_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 5396bc50445SMarcel Moolenaar char *buf, size_t bufsz) 5406bc50445SMarcel Moolenaar { 5416bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 54288007f61SAndrey V. Elsukov int i; 5436bc50445SMarcel Moolenaar 5446bc50445SMarcel Moolenaar entry = (struct g_part_mbr_entry *)baseentry; 54588007f61SAndrey V. Elsukov for (i = 0; 54688007f61SAndrey V. Elsukov i < sizeof(mbr_alias_match) / sizeof(mbr_alias_match[0]); i++) { 54788007f61SAndrey V. Elsukov if (mbr_alias_match[i].typ == entry->ent.dp_typ) 54888007f61SAndrey V. Elsukov return (g_part_alias_name(mbr_alias_match[i].alias)); 549c6b2b6fcSRui Paulo } 55088007f61SAndrey V. Elsukov snprintf(buf, bufsz, "!%d", entry->ent.dp_typ); 5516bc50445SMarcel Moolenaar return (buf); 5526bc50445SMarcel Moolenaar } 5536bc50445SMarcel Moolenaar 5546bc50445SMarcel Moolenaar static int 5556bc50445SMarcel Moolenaar g_part_mbr_write(struct g_part_table *basetable, struct g_consumer *cp) 5566bc50445SMarcel Moolenaar { 5576bc50445SMarcel Moolenaar struct g_part_entry *baseentry; 5586bc50445SMarcel Moolenaar struct g_part_mbr_entry *entry; 5596bc50445SMarcel Moolenaar struct g_part_mbr_table *table; 5606bc50445SMarcel Moolenaar u_char *p; 5616bc50445SMarcel Moolenaar int error, index; 5626bc50445SMarcel Moolenaar 5636bc50445SMarcel Moolenaar table = (struct g_part_mbr_table *)basetable; 5646bc50445SMarcel Moolenaar baseentry = LIST_FIRST(&basetable->gpt_entry); 5656bc50445SMarcel Moolenaar for (index = 1; index <= basetable->gpt_entries; index++) { 5666bc50445SMarcel Moolenaar p = table->mbr + DOSPARTOFF + (index - 1) * DOSPARTSIZE; 5676bc50445SMarcel Moolenaar entry = (baseentry != NULL && index == baseentry->gpe_index) 5686bc50445SMarcel Moolenaar ? (struct g_part_mbr_entry *)baseentry : NULL; 5696bc50445SMarcel Moolenaar if (entry != NULL && !baseentry->gpe_deleted) { 5706bc50445SMarcel Moolenaar p[0] = entry->ent.dp_flag; 5716bc50445SMarcel Moolenaar p[1] = entry->ent.dp_shd; 5726bc50445SMarcel Moolenaar p[2] = entry->ent.dp_ssect; 5736bc50445SMarcel Moolenaar p[3] = entry->ent.dp_scyl; 5746bc50445SMarcel Moolenaar p[4] = entry->ent.dp_typ; 5756bc50445SMarcel Moolenaar p[5] = entry->ent.dp_ehd; 5766bc50445SMarcel Moolenaar p[6] = entry->ent.dp_esect; 5776bc50445SMarcel Moolenaar p[7] = entry->ent.dp_ecyl; 5786bc50445SMarcel Moolenaar le32enc(p + 8, entry->ent.dp_start); 5796bc50445SMarcel Moolenaar le32enc(p + 12, entry->ent.dp_size); 5806bc50445SMarcel Moolenaar } else 5816bc50445SMarcel Moolenaar bzero(p, DOSPARTSIZE); 5826bc50445SMarcel Moolenaar 5836bc50445SMarcel Moolenaar if (entry != NULL) 5846bc50445SMarcel Moolenaar baseentry = LIST_NEXT(baseentry, gpe_entry); 5856bc50445SMarcel Moolenaar } 5866bc50445SMarcel Moolenaar 5876bc50445SMarcel Moolenaar error = g_write_data(cp, 0, table->mbr, cp->provider->sectorsize); 5886bc50445SMarcel Moolenaar return (error); 5896bc50445SMarcel Moolenaar } 590