1*614d0f20Skrw /* $OpenBSD: mbr.c,v 1.124 2023/05/17 12:59:37 krw Exp $ */
2a1705421Sweingart
3a1705421Sweingart /*
4a1705421Sweingart * Copyright (c) 1997 Tobias Weingartner
5a1705421Sweingart *
610a68084Skrw * Permission to use, copy, modify, and distribute this software for any
710a68084Skrw * purpose with or without fee is hereby granted, provided that the above
810a68084Skrw * copyright notice and this permission notice appear in all copies.
9a1705421Sweingart *
1010a68084Skrw * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1110a68084Skrw * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1210a68084Skrw * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1310a68084Skrw * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1410a68084Skrw * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1510a68084Skrw * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1610a68084Skrw * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a1705421Sweingart */
18a1705421Sweingart
19b9fc9a72Sderaadt #include <sys/param.h> /* DEV_BSIZE */
20a7568474Sderaadt #include <sys/ioctl.h>
21a7568474Sderaadt #include <sys/disklabel.h>
22a7568474Sderaadt #include <sys/dkio.h>
23729290c0Skrw
24605b5690Skrw #include <err.h>
25729290c0Skrw #include <stdio.h>
26729290c0Skrw #include <stdlib.h>
27bdf84265Skrw #include <string.h>
28abc6f793Skrw
29a5472107Skrw #include "part.h"
30199eafeaSkrw #include "disk.h"
31a1705421Sweingart #include "misc.h"
32a1705421Sweingart #include "mbr.h"
3379bcacc5Skrw #include "gpt.h"
34108d94f1Sweingart
35f43a9f23Skrw struct dos_mbr default_dmbr;
36f43a9f23Skrw
37f43a9f23Skrw void mbr_to_dos_mbr(const struct mbr *, struct dos_mbr *);
38f43a9f23Skrw void dos_mbr_to_mbr(const struct dos_mbr *, const uint64_t,
39f43a9f23Skrw const uint64_t, struct mbr *);
409317a2ddSkrw
411f546e5fSjsing void
MBR_init(struct mbr * mbr)42ac519580Skrw MBR_init(struct mbr *mbr)
434ed7cd7eSrahnds {
44d349feebSkrw struct dos_partition dp;
453f3ade34Skrw struct prt bootprt, obsdprt;
4608d01326Skrw daddr_t daddr;
471f546e5fSjsing
48dfcac45eSkrw memset(&gmbr, 0, sizeof(gmbr));
494d692ca3Skrw memset(&gh, 0, sizeof(gh));
504d692ca3Skrw memset(&gp, 0, sizeof(gp));
514d692ca3Skrw
52f43a9f23Skrw if (mbr->mbr_lba_self != 0) {
53f43a9f23Skrw /* Extended MBR - save lba's, set sig, zap everything else. */
54f43a9f23Skrw memset(mbr->mbr_code, 0, sizeof(mbr->mbr_code));
55f43a9f23Skrw memset(mbr->mbr_prt, 0, sizeof(mbr->mbr_prt));
56f43a9f23Skrw mbr->mbr_signature = DOSMBR_SIGNATURE;
57f43a9f23Skrw return;
58f43a9f23Skrw }
59f43a9f23Skrw
603f3ade34Skrw memset(&obsdprt, 0, sizeof(obsdprt));
613f3ade34Skrw memset(&bootprt, 0, sizeof(bootprt));
6207626630Skrw
63354eded8Skrw if (disk.dk_bootprt.prt_ns > 0) {
64354eded8Skrw bootprt = disk.dk_bootprt;
65354eded8Skrw } else {
663f3ade34Skrw memcpy(&dp, &default_dmbr.dmbr_parts[0], sizeof(dp));
67*614d0f20Skrw PRT_dp_to_prt(&dp, 0, 0, &bootprt);
68354eded8Skrw }
693f3ade34Skrw
703220ebedSkrw if (bootprt.prt_ns > 0) {
713220ebedSkrw /* Start OpenBSD partition immediately after bootprt. */
72d8f1450dSkrw obsdprt.prt_bs = bootprt.prt_bs + bootprt.prt_ns;
733220ebedSkrw } else if (disk.dk_heads > 1 || disk.dk_cylinders > 1) {
743220ebedSkrw /*
753220ebedSkrw * Start OpenBSD partition on power of 2 block number
763220ebedSkrw * after the first track.
773220ebedSkrw */
7808d01326Skrw daddr = 1;
793220ebedSkrw while (daddr < DL_SECTOBLK(&dl, disk.dk_sectors))
8008d01326Skrw daddr *= 2;
81dd3db818Skrw obsdprt.prt_bs = DL_BLKTOSEC(&dl, daddr);
823220ebedSkrw } else {
833220ebedSkrw /* Start OpenBSD partition immediately after MBR. */
843220ebedSkrw obsdprt.prt_bs = 1;
853220ebedSkrw }
86bad58a6dSkrw
874707d017Skrw if (obsdprt.prt_bs >= disk.dk_size) {
88bad58a6dSkrw memset(&obsdprt, 0, sizeof(obsdprt));
89bad58a6dSkrw } else {
904707d017Skrw obsdprt.prt_ns = disk.dk_size - obsdprt.prt_bs;
91bad58a6dSkrw obsdprt.prt_id = DOSPTYP_OPENBSD;
92bad58a6dSkrw if (bootprt.prt_flag != DOSACTIVE)
93bad58a6dSkrw obsdprt.prt_flag = DOSACTIVE;
94bad58a6dSkrw }
95561952b1Skrw
963f3ade34Skrw memset(mbr, 0, sizeof(*mbr));
973f3ade34Skrw memcpy(mbr->mbr_code, default_dmbr.dmbr_boot, sizeof(mbr->mbr_code));
983f3ade34Skrw mbr->mbr_prt[0] = bootprt;
993f3ade34Skrw mbr->mbr_prt[3] = obsdprt;
1003f3ade34Skrw mbr->mbr_signature = DOSMBR_SIGNATURE;
1014ed7cd7eSrahnds }
102a1705421Sweingart
103a1705421Sweingart void
dos_mbr_to_mbr(const struct dos_mbr * dmbr,const uint64_t lba_self,const uint64_t lba_firstembr,struct mbr * mbr)104f43a9f23Skrw dos_mbr_to_mbr(const struct dos_mbr *dmbr, const uint64_t lba_self,
1050cd9e2afSkrw const uint64_t lba_firstembr, struct mbr *mbr)
106a1705421Sweingart {
1073dbb6cecSkrw struct dos_partition dos_parts[NDOSPART];
1083d40667eSkrw uint8_t *p;
1093d40667eSkrw unsigned int i;
1103d40667eSkrw
1113d40667eSkrw p = (uint8_t *)dmbr;
1123d40667eSkrw mbr->mbr_dmbrzeros = 0;
1133d40667eSkrw for (i = 0; i < sizeof(struct dos_mbr) && *p == 0; i++, p++)
1143d40667eSkrw mbr->mbr_dmbrzeros++;
115a1705421Sweingart
116f43a9f23Skrw memcpy(mbr->mbr_code, dmbr->dmbr_boot, sizeof(mbr->mbr_code));
117061e6e0aSkrw mbr->mbr_lba_self = lba_self;
118061e6e0aSkrw mbr->mbr_lba_firstembr = lba_firstembr;
119f43a9f23Skrw mbr->mbr_signature = letoh16(dmbr->dmbr_sign);
120a1705421Sweingart
121f43a9f23Skrw memcpy(dos_parts, dmbr->dmbr_parts, sizeof(dos_parts));
1223dbb6cecSkrw
123c5431474Skrw for (i = 0; i < nitems(mbr->mbr_prt); i++) {
124c5431474Skrw memset(&mbr->mbr_prt[i], 0, sizeof(mbr->mbr_prt[i]));
125c5431474Skrw if (i < nitems(dmbr->dmbr_parts))
126*614d0f20Skrw PRT_dp_to_prt(&dos_parts[i], lba_self, lba_firstembr,
127061e6e0aSkrw &mbr->mbr_prt[i]);
12853f15ebcSkrw }
129c5431474Skrw }
130a1705421Sweingart
131a1705421Sweingart void
mbr_to_dos_mbr(const struct mbr * mbr,struct dos_mbr * dos_mbr)132f43a9f23Skrw mbr_to_dos_mbr(const struct mbr *mbr, struct dos_mbr *dos_mbr)
133a1705421Sweingart {
13453f15ebcSkrw struct dos_partition dos_partition;
135c5431474Skrw unsigned int i;
136a1705421Sweingart
137061e6e0aSkrw memcpy(dos_mbr->dmbr_boot, mbr->mbr_code, sizeof(dos_mbr->dmbr_boot));
13853f15ebcSkrw dos_mbr->dmbr_sign = htole16(DOSMBR_SIGNATURE);
139a1705421Sweingart
140c5431474Skrw for (i = 0; i < nitems(dos_mbr->dmbr_parts); i++) {
141c5431474Skrw memset(&dos_partition, 0, sizeof(dos_partition));
142c5431474Skrw if (i < nitems(mbr->mbr_prt)) {
143*614d0f20Skrw PRT_prt_to_dp(&mbr->mbr_prt[i], mbr->mbr_lba_self,
14499e0469cSkrw mbr->mbr_lba_firstembr, &dos_partition);
145c5431474Skrw }
14653f15ebcSkrw memcpy(&dos_mbr->dmbr_parts[i], &dos_partition,
14753f15ebcSkrw sizeof(dos_mbr->dmbr_parts[i]));
14853f15ebcSkrw }
149a1705421Sweingart }
150a1705421Sweingart
151a1705421Sweingart void
MBR_print(const struct mbr * mbr,const char * units)152859be6c9Skrw MBR_print(const struct mbr *mbr, const char *units)
153a1705421Sweingart {
1545f7fe693Skrw unsigned int i;
155a1705421Sweingart
1566c51fc53Skrw DISK_printgeometry("s");
157fba7235cSkrw
158530f0457Skrw printf("Offset: %llu\t", mbr->mbr_lba_self);
159061e6e0aSkrw printf("Signature: 0x%X\n", (int)mbr->mbr_signature);
1607b70791fSkrw PRT_print_parthdr();
161a1705421Sweingart
1625f7fe693Skrw for (i = 0; i < nitems(mbr->mbr_prt); i++)
1637b70791fSkrw PRT_print_part(i, &mbr->mbr_prt[i], units);
164a1705421Sweingart }
165a1705421Sweingart
166a1705421Sweingart int
MBR_read(const uint64_t lba_self,const uint64_t lba_firstembr,struct mbr * mbr)1671429e715Skrw MBR_read(const uint64_t lba_self, const uint64_t lba_firstembr, struct mbr *mbr)
168a1705421Sweingart {
1691429e715Skrw struct dos_mbr dos_mbr;
170a1705421Sweingart
171adf35c80Skrw if (DISK_readbytes(&dos_mbr, lba_self, sizeof(dos_mbr)))
1722a536aa2Skrw return -1;
173d1f880e6Skrw
174f43a9f23Skrw dos_mbr_to_mbr(&dos_mbr, lba_self, lba_firstembr, mbr);
1751429e715Skrw
1762a536aa2Skrw return 0;
177a1705421Sweingart }
178a1705421Sweingart
179a1705421Sweingart int
MBR_write(const struct mbr * mbr)180e79775dbSkrw MBR_write(const struct mbr *mbr)
181a1705421Sweingart {
182e79775dbSkrw struct dos_mbr dos_mbr;
183d1f880e6Skrw
184f43a9f23Skrw mbr_to_dos_mbr(mbr, &dos_mbr);
185e79775dbSkrw
186adf35c80Skrw if (DISK_writebytes(&dos_mbr, mbr->mbr_lba_self, sizeof(dos_mbr)))
187605b5690Skrw return -1;
18834be3939Skrw
18934be3939Skrw /* Refresh in-kernel disklabel from the updated disk information. */
190605b5690Skrw if (ioctl(disk.dk_fd, DIOCRLDINFO, 0) == -1)
191605b5690Skrw warn("DIOCRLDINFO");
1923f4f9081Skrw
1932a536aa2Skrw return 0;
194a1705421Sweingart }
1959ba61043Skrw
1969ba61043Skrw int
MBR_valid_prt(const struct mbr * mbr)1979ba61043Skrw MBR_valid_prt(const struct mbr *mbr)
1989ba61043Skrw {
1999ba61043Skrw uint64_t bs, ns;
2009ba61043Skrw unsigned int i, nprt;
2019ba61043Skrw unsigned char id;
2029ba61043Skrw
2033d40667eSkrw if (mbr->mbr_dmbrzeros == sizeof(struct dos_mbr))
2043d40667eSkrw return 1; /* All zeros struct dos_mbr is editable. */
2053d40667eSkrw
2069ba61043Skrw nprt = 0;
2075f7fe693Skrw for (i = 0; i < nitems(mbr->mbr_prt); i++) {
2089ba61043Skrw bs = mbr->mbr_prt[i].prt_bs;
2099ba61043Skrw ns = mbr->mbr_prt[i].prt_ns;
2109ba61043Skrw id = mbr->mbr_prt[i].prt_id;
2119ba61043Skrw if ((bs == 0 && ns == 0 && id == 0) ||
2129ba61043Skrw (bs < DL_GETDSIZE(&dl) && ns > 0 && ns <= DL_GETDSIZE(&dl)))
2139ba61043Skrw nprt++;
2149ba61043Skrw }
2159ba61043Skrw
2169ba61043Skrw return nprt > 0 && mbr->mbr_signature == DOSMBR_SIGNATURE;
2179ba61043Skrw }
218