1 /* $OpenBSD: mbr.c,v 1.114 2021/12/11 20:09:28 krw Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Tobias Weingartner 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> /* DEV_BSIZE */ 20 #include <sys/ioctl.h> 21 #include <sys/disklabel.h> 22 #include <sys/dkio.h> 23 24 #include <err.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "part.h" 30 #include "disk.h" 31 #include "misc.h" 32 #include "mbr.h" 33 #include "gpt.h" 34 35 struct dos_mbr default_dmbr; 36 37 void mbr_to_dos_mbr(const struct mbr *, struct dos_mbr *); 38 void dos_mbr_to_mbr(const struct dos_mbr *, const uint64_t, 39 const uint64_t, struct mbr *); 40 41 void 42 MBR_init(struct mbr *mbr) 43 { 44 struct dos_partition dp; 45 struct prt bootprt, obsdprt; 46 daddr_t daddr; 47 48 memset(&gmbr, 0, sizeof(gmbr)); 49 memset(&gh, 0, sizeof(gh)); 50 memset(&gp, 0, sizeof(gp)); 51 52 if (mbr->mbr_lba_self != 0) { 53 /* Extended MBR - save lba's, set sig, zap everything else. */ 54 memset(mbr->mbr_code, 0, sizeof(mbr->mbr_code)); 55 memset(mbr->mbr_prt, 0, sizeof(mbr->mbr_prt)); 56 mbr->mbr_signature = DOSMBR_SIGNATURE; 57 return; 58 } 59 60 memset(&obsdprt, 0, sizeof(obsdprt)); 61 memset(&bootprt, 0, sizeof(bootprt)); 62 63 if (disk.dk_bootprt.prt_ns > 0) { 64 bootprt = disk.dk_bootprt; 65 } else { 66 memcpy(&dp, &default_dmbr.dmbr_parts[0], sizeof(dp)); 67 PRT_parse(&dp, 0, 0, &bootprt); 68 } 69 70 if (bootprt.prt_ns > 0) { 71 /* Start OpenBSD partition immediately after bootprt. */ 72 obsdprt.prt_bs = bootprt.prt_bs + bootprt.prt_ns; 73 } else if (disk.dk_heads > 1 || disk.dk_cylinders > 1) { 74 /* 75 * Start OpenBSD partition on power of 2 block number 76 * after the first track. 77 */ 78 daddr = 1; 79 while (daddr < DL_SECTOBLK(&dl, disk.dk_sectors)) 80 daddr *= 2; 81 obsdprt.prt_bs = DL_BLKTOSEC(&dl, daddr); 82 } else { 83 /* Start OpenBSD partition immediately after MBR. */ 84 obsdprt.prt_bs = 1; 85 } 86 87 if (obsdprt.prt_bs >= disk.dk_size) { 88 memset(&obsdprt, 0, sizeof(obsdprt)); 89 } else { 90 obsdprt.prt_ns = disk.dk_size - obsdprt.prt_bs; 91 obsdprt.prt_id = DOSPTYP_OPENBSD; 92 if (bootprt.prt_flag != DOSACTIVE) 93 obsdprt.prt_flag = DOSACTIVE; 94 PRT_fix_CHS(&obsdprt); 95 } 96 97 PRT_fix_CHS(&bootprt); 98 99 memset(mbr, 0, sizeof(*mbr)); 100 memcpy(mbr->mbr_code, default_dmbr.dmbr_boot, sizeof(mbr->mbr_code)); 101 mbr->mbr_prt[0] = bootprt; 102 mbr->mbr_prt[3] = obsdprt; 103 mbr->mbr_signature = DOSMBR_SIGNATURE; 104 } 105 106 void 107 dos_mbr_to_mbr(const struct dos_mbr *dmbr, const uint64_t lba_self, 108 const uint64_t lba_firstembr, struct mbr *mbr) 109 { 110 struct dos_partition dos_parts[NDOSPART]; 111 int i; 112 113 memcpy(mbr->mbr_code, dmbr->dmbr_boot, sizeof(mbr->mbr_code)); 114 mbr->mbr_lba_self = lba_self; 115 mbr->mbr_lba_firstembr = lba_firstembr; 116 mbr->mbr_signature = letoh16(dmbr->dmbr_sign); 117 118 memcpy(dos_parts, dmbr->dmbr_parts, sizeof(dos_parts)); 119 120 for (i = 0; i < NDOSPART; i++) 121 PRT_parse(&dos_parts[i], lba_self, lba_firstembr, 122 &mbr->mbr_prt[i]); 123 } 124 125 void 126 mbr_to_dos_mbr(const struct mbr *mbr, struct dos_mbr *dos_mbr) 127 { 128 struct dos_partition dos_partition; 129 int i; 130 131 memcpy(dos_mbr->dmbr_boot, mbr->mbr_code, sizeof(dos_mbr->dmbr_boot)); 132 dos_mbr->dmbr_sign = htole16(DOSMBR_SIGNATURE); 133 134 for (i = 0; i < NDOSPART; i++) { 135 PRT_make(&mbr->mbr_prt[i], mbr->mbr_lba_self, mbr->mbr_lba_firstembr, 136 &dos_partition); 137 memcpy(&dos_mbr->dmbr_parts[i], &dos_partition, 138 sizeof(dos_mbr->dmbr_parts[i])); 139 } 140 } 141 142 void 143 MBR_print(const struct mbr *mbr, const char *units) 144 { 145 int i; 146 147 DISK_printgeometry("s"); 148 149 printf("Offset: %lld\t", (long long)mbr->mbr_lba_self); 150 printf("Signature: 0x%X\n", (int)mbr->mbr_signature); 151 PRT_print(0, NULL, units); 152 153 for (i = 0; i < NDOSPART; i++) 154 PRT_print(i, &mbr->mbr_prt[i], units); 155 } 156 157 int 158 MBR_read(const uint64_t lba_self, const uint64_t lba_firstembr, struct mbr *mbr) 159 { 160 struct dos_mbr dos_mbr; 161 char *secbuf; 162 163 secbuf = DISK_readsectors(lba_self, 1); 164 if (secbuf == NULL) 165 return -1; 166 167 memcpy(&dos_mbr, secbuf, sizeof(dos_mbr)); 168 free(secbuf); 169 170 dos_mbr_to_mbr(&dos_mbr, lba_self, lba_firstembr, mbr); 171 172 return 0; 173 } 174 175 int 176 MBR_write(const struct mbr *mbr) 177 { 178 struct dos_mbr dos_mbr; 179 char *secbuf; 180 int rslt; 181 182 secbuf = DISK_readsectors(mbr->mbr_lba_self, 1); 183 if (secbuf == NULL) 184 return -1; 185 186 mbr_to_dos_mbr(mbr, &dos_mbr); 187 memcpy(secbuf, &dos_mbr, sizeof(dos_mbr)); 188 189 rslt = DISK_writesectors(secbuf, mbr->mbr_lba_self, 1); 190 free(secbuf); 191 if (rslt) 192 return -1; 193 194 /* Refresh in-kernel disklabel from the updated disk information. */ 195 if (ioctl(disk.dk_fd, DIOCRLDINFO, 0) == -1) 196 warn("DIOCRLDINFO"); 197 198 return 0; 199 } 200