Annotation of src/distrib/utils/sysinst/mbr.c, Revision 1.40
1.40 ! dsl 1: /* $NetBSD: mbr.c,v 1.39 2003/06/13 11:57:29 dsl Exp $ */
1.1 phil 2:
3: /*
4: * Copyright 1997 Piermont Information Systems Inc.
5: * All rights reserved.
6: *
7: * Written by Philip A. Nelson for Piermont Information Systems Inc.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
1.16 cgd 19: * This product includes software developed for the NetBSD Project by
1.1 phil 20: * Piermont Information Systems Inc.
21: * 4. The name of Piermont Information Systems Inc. may not be used to endorse
22: * or promote products derived from this software without specific prior
23: * written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
26: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28: * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
29: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35: * THE POSSIBILITY OF SUCH DAMAGE.
36: *
37: */
38:
1.10 fvdl 39: /*
40: * Following applies to the geometry guessing code
41: */
42:
43: /*
44: * Mach Operating System
45: * Copyright (c) 1992 Carnegie Mellon University
46: * All Rights Reserved.
47: *
48: * Permission to use, copy, modify and distribute this software and its
49: * documentation is hereby granted, provided that both the copyright
50: * notice and this permission notice appear in all copies of the
51: * software, derivative works or modified versions, and any portions
52: * thereof, and that both notices appear in supporting documentation.
53: *
54: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
55: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
56: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
57: *
58: * Carnegie Mellon requests users of this software to return to
59: *
60: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
61: * School of Computer Science
62: * Carnegie Mellon University
63: * Pittsburgh PA 15213-3890
64: *
65: * any improvements or extensions that they make and grant Carnegie Mellon
66: * the rights to redistribute these changes.
67: */
68:
1.6 jonathan 69: /* mbr.c -- DOS Master Boot Record editing code */
1.1 phil 70:
1.10 fvdl 71: #include <sys/param.h>
72: #include <sys/types.h>
1.1 phil 73: #include <stdio.h>
1.10 fvdl 74: #include <unistd.h>
75: #include <fcntl.h>
1.6 jonathan 76: #include <util.h>
1.1 phil 77: #include "defs.h"
1.10 fvdl 78: #include "mbr.h"
1.1 phil 79: #include "md.h"
80: #include "msg_defs.h"
81: #include "menu_defs.h"
1.10 fvdl 82: #include "endian.h"
1.1 phil 83:
84: struct part_id {
85: int id;
86: char *name;
87: } part_ids[] = {
88: {0, "unused"},
1.20 soren 89: {MBR_PTYPE_FAT12, "DOS FAT12"},
90: {MBR_PTYPE_FAT16S, "DOS FAT16, <32M"},
91: {MBR_PTYPE_EXT, "Extended partition"},
92: {MBR_PTYPE_FAT16B, "DOS FAT16, >32M"},
1.10 fvdl 93: {MBR_PTYPE_NTFS, "NTFS"},
1.20 soren 94: {MBR_PTYPE_FAT32, "Windows FAT32"},
95: {MBR_PTYPE_FAT32L, "Windows FAT32, LBA"},
96: {MBR_PTYPE_FAT16L, "Windows FAT16, LBA"},
97: {MBR_PTYPE_EXT_LBA, "Extended partition, LBA"},
1.10 fvdl 98: {MBR_PTYPE_LNXSWAP, "Linux swap"},
99: {MBR_PTYPE_LNXEXT2, "Linux native"},
1.20 soren 100: {MBR_PTYPE_NTFSVOL, "NTFS volume set"},
1.10 fvdl 101: {MBR_PTYPE_386BSD, "old NetBSD/FreeBSD/386BSD"},
102: {MBR_PTYPE_NETBSD, "NetBSD"},
1.1 phil 103: {-1, "Unknown"},
104: };
105:
1.10 fvdl 106: int dosptyp_nbsd = MBR_PTYPE_NETBSD;
107:
1.38 dsl 108: static int get_mapping(struct mbr_partition *, int, int *, int *, int *,
1.40 ! dsl 109: unsigned long *);
1.38 dsl 110: static void convert_mbr_chs(int, int, int, u_int8_t *, u_int8_t *,
1.25 mrg 111: u_int8_t *, u_int32_t);
1.6 jonathan 112:
1.34 dsl 113: #ifdef BOOTSEL
114: static int defbootselpart, defbootseldisk;
115: struct mbr_bootsel *mbs;
116: #endif
1.6 jonathan 117:
118: /*
119: * get C/H/S geometry from user via menu interface and
120: * store in globals.
121: */
1.7 mrg 122: void
1.38 dsl 123: set_bios_geom(int cyl, int head, int sec)
1.6 jonathan 124: {
125: char res[80];
1.7 mrg 126:
1.6 jonathan 127: msg_display_add(MSG_setbiosgeom);
1.10 fvdl 128: snprintf(res, 80, "%d", cyl);
1.8 rvb 129: msg_prompt_add(MSG_cylinders, res, res, 80);
1.6 jonathan 130: bcyl = atoi(res);
1.8 rvb 131:
1.10 fvdl 132: snprintf(res, 80, "%d", head);
1.8 rvb 133: msg_prompt_add(MSG_heads, res, res, 80);
1.6 jonathan 134: bhead = atoi(res);
1.8 rvb 135:
1.10 fvdl 136: snprintf(res, 80, "%d", sec);
1.8 rvb 137: msg_prompt_add(MSG_sectors, res, res, 80);
1.6 jonathan 138: bsec = atoi(res);
139: }
140:
1.30 christos 141: #ifdef notdef
1.7 mrg 142: void
1.38 dsl 143: disp_cur_geom(void)
1.7 mrg 144: {
1.6 jonathan 145:
146: msg_display_add(MSG_realgeom, dlcyl, dlhead, dlsec);
147: msg_display_add(MSG_biosgeom, bcyl, bhead, bsec);
148: }
1.30 christos 149: #endif
1.6 jonathan 150:
151:
152: /*
153: * Then, the partition stuff...
154: */
155: int
1.38 dsl 156: otherpart(int id)
1.6 jonathan 157: {
1.7 mrg 158:
1.10 fvdl 159: return (id != 0 && id != MBR_PTYPE_386BSD && id != MBR_PTYPE_NETBSD);
1.6 jonathan 160: }
161:
162: int
1.38 dsl 163: ourpart(int id)
1.6 jonathan 164: {
1.7 mrg 165:
1.10 fvdl 166: return (id == MBR_PTYPE_386BSD || id == MBR_PTYPE_NETBSD);
1.6 jonathan 167: }
168:
169: /*
170: * Let user change incore Master Boot Record partitions via menu.
171: */
1.7 mrg 172: int
1.38 dsl 173: edit_mbr(struct mbr_sector *mbr)
1.6 jonathan 174: {
175: int i, j;
176:
177: /* Ask full/part */
1.10 fvdl 178:
179: /* XXX this sucks ("part" is used in menus, no param passing there) */
1.32 dsl 180: part = &mbr->mbr_parts[0];
1.7 mrg 181: msg_display(MSG_fullpart, diskdev);
1.37 dsl 182: process_menu(MENU_fullpart, NULL);
1.6 jonathan 183:
184: /* DOS fdisk label checking and value setting. */
185: if (usefull) {
186: int otherparts = 0;
187: int ourparts = 0;
188:
189: /* Count nonempty, non-BSD partitions. */
1.10 fvdl 190: for (i = 0; i < NMBRPART; i++) {
1.14 bouyer 191: otherparts += otherpart(part[i].mbrp_typ);
1.6 jonathan 192: /* check for dualboot *bsd too */
1.14 bouyer 193: ourparts += ourpart(part[i].mbrp_typ);
1.6 jonathan 194: }
195:
196: /* Ask if we really want to blow away non-NetBSD stuff */
197: if (otherparts != 0 || ourparts > 1) {
1.7 mrg 198: msg_display(MSG_ovrwrite);
1.37 dsl 199: process_menu(MENU_noyes, NULL);
1.6 jonathan 200: if (!yesno) {
1.9 garbled 201: if (logging)
1.29 fvdl 202: (void)fprintf(logfp, "User answered no to destroy other data, aborting.\n");
1.6 jonathan 203: return 0;
204: }
205: }
206:
207: /* Set the partition information for full disk usage. */
1.14 bouyer 208: part[0].mbrp_typ = part[0].mbrp_flag = 0;
209: part[0].mbrp_start = part[0].mbrp_size = 0;
210: part[1].mbrp_typ = part[0].mbrp_flag = 0;
211: part[1].mbrp_start = part[0].mbrp_size = 0;
212: part[2].mbrp_typ = part[0].mbrp_flag = 0;
213: part[2].mbrp_start = part[0].mbrp_size = 0;
1.10 fvdl 214: part[3].mbrp_typ = dosptyp_nbsd;
1.35 dsl 215: part[3].mbrp_size = dlsize - bsec;
1.10 fvdl 216: part[3].mbrp_start = bsec;
217: part[3].mbrp_flag = 0x80;
1.6 jonathan 218:
219: ptstart = bsec;
1.35 dsl 220: ptsize = dlsize - bsec;
1.6 jonathan 221: activepart = 3;
222: } else {
223: int numbsd, overlap;
224: int numfreebsd, freebsdpart; /* dual-boot */
225:
226: /* Ask for sizes, which partitions, ... */
1.21 fvdl 227: ask_sizemult(bcylsize);
1.6 jonathan 228: bsdpart = freebsdpart = -1;
229: activepart = -1;
1.35 dsl 230: for (i = 0; i < NMBRPART; i++) {
1.13 bouyer 231: if (part[i].mbrp_flag != 0) {
1.6 jonathan 232: activepart = i;
1.13 bouyer 233: part[i].mbrp_flag = 0;
234: }
1.35 dsl 235: }
1.6 jonathan 236: do {
1.37 dsl 237: process_menu(MENU_editparttable, NULL);
1.6 jonathan 238: numbsd = 0;
239: bsdpart = -1;
240: freebsdpart = -1;
241: numfreebsd = 0;
242: overlap = 0;
243: yesno = 0;
1.33 dsl 244: for (i=0; i < NMBRPART; i++) {
1.7 mrg 245: /* Count 386bsd/FreeBSD/NetBSD(old) partitions */
1.10 fvdl 246: if (part[i].mbrp_typ == MBR_PTYPE_386BSD) {
1.6 jonathan 247: freebsdpart = i;
248: numfreebsd++;
249: }
250: /* Count NetBSD-only partitions */
1.10 fvdl 251: if (part[i].mbrp_typ == MBR_PTYPE_NETBSD) {
1.33 dsl 252: if (bsdpart == -1)
253: bsdpart = i;
1.6 jonathan 254: numbsd++;
255: }
1.33 dsl 256: for (j = i + 1; j < NMBRPART; j++)
257: if (partsoverlap(part, i, j))
1.6 jonathan 258: overlap = 1;
259: }
260:
261: /* If no new-NetBSD partition, use 386bsd instead */
262: if (numbsd == 0 && numfreebsd > 0) {
263: numbsd = numfreebsd;
264: bsdpart = freebsdpart;
265: /* XXX check partition type? */
266: }
267:
268: /* Check for overlap or multiple native partitions */
269: if (overlap || numbsd != 1) {
1.7 mrg 270: msg_display(MSG_reeditpart);
1.37 dsl 271: process_menu(MENU_yesno, NULL);
1.6 jonathan 272: }
273: } while (yesno && (numbsd != 1 || overlap));
1.11 fvdl 274:
1.6 jonathan 275:
276: if (numbsd == 0) {
1.7 mrg 277: msg_display(MSG_nobsdpart);
1.37 dsl 278: process_menu(MENU_ok, NULL);
1.6 jonathan 279: return 0;
280: }
281:
282: if (numbsd > 1) {
1.7 mrg 283: msg_display(MSG_multbsdpart, bsdpart);
1.37 dsl 284: process_menu(MENU_ok, NULL);
1.6 jonathan 285: }
1.15 fvdl 286:
287: if (activepart == -1) {
288: msg_display(MSG_noactivepart);
1.37 dsl 289: process_menu(MENU_yesno, NULL);
1.15 fvdl 290: if (yesno)
291: part[bsdpart].mbrp_flag = 0x80;
292: } else
293: part[activepart].mbrp_flag = 0x80;
294:
295: if (bsdpart == freebsdpart) {
296: msg_display(MSG_upgradeparttype);
1.37 dsl 297: process_menu(MENU_yesno, NULL);
1.15 fvdl 298: if (yesno)
299: part[bsdpart].mbrp_typ = dosptyp_nbsd;
300: }
1.6 jonathan 301:
1.10 fvdl 302: ptstart = part[bsdpart].mbrp_start;
303: ptsize = part[bsdpart].mbrp_size;
1.6 jonathan 304:
305: /* Ask if a boot selector is wanted. XXXX */
306: }
307:
308: return 1;
309: }
310:
1.33 dsl 311: void
312: edit_ptn_bounds(void)
313: {
314: char buf[40]; int start, size, inp, partn;
315:
316: msg_table_add(MSG_mbrpart_start_special);
317: msg_prompt_add(MSG_start, NULL, buf, sizeof buf);
318: inp = atoi(buf);
319: /*
320: * -0, -1, -2, -3: start at end of part # given
321: * 0: start of disk.
322: */
323: if ((inp == 0 && buf[0] == '-') || (inp < 0 && inp >= -3)) {
324: partn = -inp;
325: start = part[partn].mbrp_start + part[partn].mbrp_size;
326: } else if (inp == 0)
327: start = bsec;
328: else
329: start = NUMSEC(inp, sizemult, dlcylsize);
330:
331: if (sizemult > 1 && start < bsec)
332: start = bsec;
333: msg_table_add(MSG_mbrpart_size_special);
1.38 dsl 334: msg_prompt_add(MSG_size, NULL, buf, 40);
1.33 dsl 335: inp = atoi(buf);
336: /*
337: * -0, -1, -2, -3: until start of part # given
338: * 0: end of disk
339: */
340: if ((inp == 0 && buf[0] == '-') || (inp < 0 && inp >= -3)) {
341: partn = -inp;
342: size = part[partn].mbrp_start - start;
343: } else if (inp == 0)
344: size = dlsize - start;
345: else
346: size = NUMSEC(inp, sizemult, dlcylsize);
347: if (sizemult > 1 && start == bsec)
348: size -= bsec;
1.35 dsl 349: if (start + size > dlsize)
350: size = dlsize - start;
1.33 dsl 351: if (size < 0) {
352: size = 0;
353: start = 0;
354: }
355: part[editpart].mbrp_start = start;
356: part[editpart].mbrp_size = size;
357: }
358:
1.7 mrg 359: int
1.38 dsl 360: partsoverlap(struct mbr_partition *part, int i, int j)
1.1 phil 361: {
1.7 mrg 362:
1.28 mrg 363: /*
364: * If the size or type of either partition is zero, they don't
365: * overlap by definition.
366: */
367: if (part[i].mbrp_size == 0 || part[j].mbrp_size == 0 ||
368: part[i].mbrp_typ == 0 || part[j].mbrp_typ == 0)
1.1 phil 369: return 0;
370:
1.2 phil 371: return
1.10 fvdl 372: (part[i].mbrp_start < part[j].mbrp_start &&
373: part[i].mbrp_start + part[i].mbrp_size > part[j].mbrp_start)
1.1 phil 374: ||
1.10 fvdl 375: (part[i].mbrp_start > part[j].mbrp_start &&
376: part[i].mbrp_start < part[j].mbrp_start + part[j].mbrp_size)
1.1 phil 377: ||
1.10 fvdl 378: (part[i].mbrp_start == part[j].mbrp_start);
1.1 phil 379: }
380:
1.15 fvdl 381: char *
1.38 dsl 382: get_partname(int i)
1.15 fvdl 383: {
384: int j;
1.34 dsl 385: static char unknown[32];
1.15 fvdl 386:
1.34 dsl 387: for (j = 0; part_ids[j].id != -1; j++)
388: if (part_ids[j].id == part[i].mbrp_typ)
389: return part_ids[j].name;
1.15 fvdl 390:
1.34 dsl 391: snprintf(unknown, sizeof unknown, "Unknown (%d)", part[i].mbrp_typ);
392: return unknown;
1.15 fvdl 393: }
394:
1.7 mrg 395: void
1.38 dsl 396: disp_cur_part(struct mbr_partition *part, int sel, int disp)
1.1 phil 397: {
1.15 fvdl 398: int i, start, stop, rsize, rend;
1.1 phil 399:
400: if (disp < 0)
401: start = 0, stop = 4;
402: else
403: start = disp, stop = disp+1;
1.23 fvdl 404: msg_table_add(MSG_part_header, dlsize/sizemult, multname, multname,
405: multname, multname);
1.7 mrg 406: for (i = start; i < stop; i++) {
407: if (sel == i)
408: msg_standout();
1.23 fvdl 409: if (part[i].mbrp_typ == 0 ||
410: (part[i].mbrp_size == 0 && part[i].mbrp_start == 0))
1.17 cgd 411: msg_table_add(MSG_part_row_start_unused, i);
1.4 fvdl 412: else {
1.10 fvdl 413: rsize = part[i].mbrp_size / sizemult;
414: if (part[i].mbrp_size % sizemult)
1.4 fvdl 415: rsize++;
1.10 fvdl 416: rend = (part[i].mbrp_start + part[i].mbrp_size) / sizemult;
1.24 hubertf 417: if ((part[i].mbrp_start + part[i].mbrp_size) % sizemult)
1.4 fvdl 418: rend++;
1.17 cgd 419: msg_table_add(MSG_part_row_start_used, i,
1.27 grant 420: part[i].mbrp_start / sizemult, rend, rsize);
1.4 fvdl 421: }
1.17 cgd 422: msg_table_add(MSG_part_row_end, get_partname(i));
1.10 fvdl 423: if (sel == i)
424: msg_standend();
425: }
426: }
427:
428: int
1.38 dsl 429: read_mbr(const char *disk, mbr_sector_t *mbr, size_t len)
1.10 fvdl 430: {
431: char diskpath[MAXPATHLEN];
432: int fd, i;
433: struct mbr_partition *mbrp;
434:
435: /* Open the disk. */
436: fd = opendisk(disk, O_RDONLY, diskpath, sizeof(diskpath), 0);
437: if (fd < 0)
438: return -1;
439:
1.30 christos 440: if (lseek(fd, (off_t)(MBR_BBSECTOR * MBR_SECSIZE), SEEK_SET) < 0) {
1.10 fvdl 441: close(fd);
442: return -1;
443: }
1.32 dsl 444: if (read(fd, mbr, len) < len) {
1.10 fvdl 445: close(fd);
446: return -1;
447: }
448:
1.32 dsl 449: if (valid_mbr(mbr)) {
450: mbrp = &mbr->mbr_parts[0];
1.10 fvdl 451: for (i = 0; i < NMBRPART; i++) {
452: if (mbrp[i].mbrp_typ != 0) {
453: mbrp[i].mbrp_start =
454: le_to_native32(mbrp[i].mbrp_start);
455: mbrp[i].mbrp_size =
456: le_to_native32(mbrp[i].mbrp_size);
1.26 mrg 457: } else {
458: /* type is unused, discard scum */
459: mbrp[i].mbrp_start = 0;
460: mbrp[i].mbrp_size = 0;
1.10 fvdl 461: }
462: }
463: }
464:
465: (void)close(fd);
466: return 0;
467: }
468:
469: int
1.38 dsl 470: write_mbr(const char *disk, mbr_sector_t *mbr, size_t len, int convert)
1.10 fvdl 471: {
472: char diskpath[MAXPATHLEN];
473: int fd, i, ret = 0;
474: struct mbr_partition *mbrp;
475: u_int32_t pstart, psize;
476:
477: /* Open the disk. */
478: fd = opendisk(disk, O_WRONLY, diskpath, sizeof(diskpath), 0);
479: if (fd < 0)
480: return -1;
481:
1.30 christos 482: if (lseek(fd, (off_t)(MBR_BBSECTOR * MBR_SECSIZE), SEEK_SET) < 0) {
1.10 fvdl 483: close(fd);
484: return -1;
485: }
486:
1.32 dsl 487: mbrp = &mbr->mbr_parts[0];
1.10 fvdl 488: for (i = 0; i < NMBRPART; i++) {
1.14 bouyer 489: if (mbrp[i].mbrp_start == 0 &&
490: mbrp[i].mbrp_size == 0) {
491: mbrp[i].mbrp_scyl = 0;
492: mbrp[i].mbrp_shd = 0;
493: mbrp[i].mbrp_ssect = 0;
494: mbrp[i].mbrp_ecyl = 0;
495: mbrp[i].mbrp_ehd = 0;
496: mbrp[i].mbrp_esect = 0;
497: } else {
1.10 fvdl 498: pstart = mbrp[i].mbrp_start;
499: psize = mbrp[i].mbrp_size;
500: mbrp[i].mbrp_start = native_to_le32(pstart);
501: mbrp[i].mbrp_size = native_to_le32(psize);
1.18 fvdl 502: if (convert) {
503: convert_mbr_chs(bcyl, bhead, bsec,
504: &mbrp[i].mbrp_scyl, &mbrp[i].mbrp_shd,
505: &mbrp[i].mbrp_ssect, pstart);
506: convert_mbr_chs(bcyl, bhead, bsec,
507: &mbrp[i].mbrp_ecyl, &mbrp[i].mbrp_ehd,
1.19 fvdl 508: &mbrp[i].mbrp_esect, pstart + psize - 1);
1.18 fvdl 509: }
1.10 fvdl 510: }
511: }
512:
1.32 dsl 513: if (write(fd, mbr, len) < 0)
1.10 fvdl 514: ret = -1;
515:
516: (void)close(fd);
517: return ret;
518: }
519:
520: int
1.38 dsl 521: valid_mbr(mbr_sector_t *mbr)
1.10 fvdl 522: {
523:
1.32 dsl 524: return (le_to_native16(mbr->mbr_signature) == MBR_MAGIC);
1.10 fvdl 525: }
526:
527: static void
1.38 dsl 528: convert_mbr_chs(int cyl, int head, int sec,
529: u_int8_t *cylp, u_int8_t *headp, u_int8_t *secp,
530: u_int32_t relsecs)
1.10 fvdl 531: {
532: unsigned int tcyl, temp, thead, tsec;
533:
1.22 fvdl 534: temp = cyl * head * sec - 1;
535: if (relsecs >= temp)
536: relsecs = temp;
537:
1.10 fvdl 538: temp = head * sec;
539: tcyl = relsecs / temp;
540:
541: relsecs %= temp;
542: thead = relsecs / sec;
543:
544: tsec = (relsecs % sec) + 1;
545:
546: *cylp = MBR_PUT_LSCYL(tcyl);
547: *headp = thead;
548: *secp = MBR_PUT_MSCYLANDSEC(tcyl, tsec);
549: }
550:
551: /*
552: * This function is ONLY to be used as a last resort to provide a
553: * hint for the user. Ports should provide a more reliable way
554: * of getting the BIOS geometry. The i386 code, for example,
555: * uses the BIOS geometry as passed on from the bootblocks,
556: * and only uses this as a hint to the user when that information
557: * is not present, or a match could not be made with a NetBSD
558: * device.
559: */
1.40 ! dsl 560:
! 561: #define MAXCYL 1023 /* Possibly 1024 */
! 562: #define MAXHEAD 255 /* Possibly 256 */
! 563: #define MAXSECTOR 63
! 564:
1.10 fvdl 565: int
1.38 dsl 566: guess_biosgeom_from_mbr(mbr_sector_t *mbr, int *cyl, int *head, int *sec)
1.10 fvdl 567: {
1.32 dsl 568: struct mbr_partition *parts = &mbr->mbr_parts[0];
1.40 ! dsl 569: int xcylinders, xheads, xsectors, i, j;
1.10 fvdl 570: int c1, h1, s1, c2, h2, s2;
1.40 ! dsl 571: unsigned long a1, a2;
! 572: uint64_t num, denom;
! 573:
! 574: /*
! 575: * The physical parameters may be invalid as bios geometry.
! 576: * If we cannot determine the actual bios geometry, we are
! 577: * better off picking a likely 'faked' geometry than leaving
! 578: * the invalid physical one.
! 579: */
1.10 fvdl 580:
1.40 ! dsl 581: xcylinders = dlcyl;
! 582: xheads = dlhead;
! 583: xsectors = dlsec;
! 584: if (xcylinders > MAXCYL || xheads > MAXHEAD || xsectors > MAXSECTOR) {
! 585: xsectors = MAXSECTOR;
! 586: xheads = MAXHEAD;
! 587: xcylinders = disk->dd_totsec / (MAXSECTOR * MAXHEAD);
! 588: if (xcylinders > MAXCYL)
! 589: xcylinders = MAXCYL;
! 590: }
! 591: *cyl = xcylinders;
! 592: *head = xheads;
! 593: *sec = xsectors;
! 594:
! 595: xheads = -1;
1.10 fvdl 596:
597: /* Try to deduce the number of heads from two different mappings. */
1.40 ! dsl 598: for (i = 0; i < NMBRPART * 2 - 1; i++) {
1.10 fvdl 599: if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0)
600: continue;
1.40 ! dsl 601: for (j = i + 1; j < NMBRPART * 2; j++) {
1.10 fvdl 602: if (get_mapping(parts, j, &c2, &h2, &s2, &a2) < 0)
603: continue;
1.40 ! dsl 604: a1 -= s1;
! 605: a2 -= s2;
! 606: num = (uint64_t)h1 * a2 - (quad_t)h2 * a1;
! 607: denom = (uint64_t)c2 * a1 - (quad_t)c1 * a2;
1.10 fvdl 608: if (denom != 0 && num % denom == 0) {
1.40 ! dsl 609: xheads = (int)(num / denom);
! 610: xsectors = a1 / (c1 * xheads + h1);
1.10 fvdl 611: break;
612: }
613: }
1.40 ! dsl 614: if (xheads != -1)
1.10 fvdl 615: break;
616: }
617:
1.40 ! dsl 618: if (xheads == -1)
1.10 fvdl 619: return -1;
620:
621: /*
622: * Estimate the number of cylinders.
623: * XXX relies on get_disks having been called.
624: */
1.40 ! dsl 625: xcylinders = disk->dd_totsec / xheads / xsectors;
1.10 fvdl 626:
627: /* Now verify consistency with each of the partition table entries.
628: * Be willing to shove cylinders up a little bit to make things work,
629: * but translation mismatches are fatal. */
630: for (i = 0; i < NMBRPART * 2; i++) {
631: if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0)
632: continue;
1.40 ! dsl 633: if (xsectors * (c1 * xheads + h1) + s1 != a1)
1.10 fvdl 634: return -1;
1.40 ! dsl 635: if (c1 >= xcylinders)
! 636: xcylinders = c1 + 1;
1.10 fvdl 637: }
638:
1.40 ! dsl 639: /*
! 640: * Everything checks out. Reset the geometry to use for further
! 641: * calculations.
! 642: */
! 643: *cyl = MIN(xcylinders, MAXCYL);
! 644: *head = xheads;
! 645: *sec = xsectors;
1.10 fvdl 646: return 0;
647: }
648:
649: static int
1.38 dsl 650: get_mapping(mbr_partition_t *parts, int i,
1.40 ! dsl 651: int *cylinder, int *head, int *sector, unsigned long *absolute)
1.10 fvdl 652: {
1.30 christos 653: struct mbr_partition *apart = &parts[i / 2];
1.10 fvdl 654:
1.30 christos 655: if (apart->mbrp_typ == 0)
1.10 fvdl 656: return -1;
657: if (i % 2 == 0) {
1.31 shin 658: *cylinder = MBR_PCYL(apart->mbrp_scyl, apart->mbrp_ssect);
1.30 christos 659: *head = apart->mbrp_shd;
660: *sector = MBR_PSECT(apart->mbrp_ssect) - 1;
1.40 ! dsl 661: *absolute = le32toh(apart->mbrp_start);
1.10 fvdl 662: } else {
1.30 christos 663: *cylinder = MBR_PCYL(apart->mbrp_ecyl, apart->mbrp_esect);
664: *head = apart->mbrp_ehd;
665: *sector = MBR_PSECT(apart->mbrp_esect) - 1;
1.40 ! dsl 666: *absolute = le32toh(apart->mbrp_start)
! 667: + le32toh(apart->mbrp_size) - 1;
1.3 phil 668: }
1.40 ! dsl 669: /* Sanity check the data against max values */
! 670: if ((((*cylinder * MAXHEAD) + *head) * MAXSECTOR + *sector) < *absolute)
! 671: /* cannot be a CHS mapping */
! 672: return -1;
! 673:
1.10 fvdl 674: return 0;
1.1 phil 675: }
1.33 dsl 676:
677: #ifdef BOOTSEL
678:
679: void
680: disp_bootsel(void)
681: {
682: int i;
683:
684: msg_display(MSG_configbootsel);
685: msg_table_add(MSG_bootsel_header);
1.34 dsl 686: for (i = 0; i < NMBRPART; i++) {
1.33 dsl 687: msg_table_add(MSG_bootsel_row, i, get_partname(i),
688: mbs->mbrb_nametab[i]);
689: }
690: msg_display_add(MSG_newline);
691:
692: msg_display_add(MSG_bootseltimeout, (10 * mbs->mbrb_timeo + 9) / 182);
693: msg_display_add(MSG_defbootselopt);
694: if (mbs->mbrb_defkey == SCAN_ENTER)
695: msg_display_add(MSG_defbootseloptactive);
1.34 dsl 696: else if (mbs->mbrb_defkey < (SCAN_1 + 10))
1.33 dsl 697: msg_display_add(MSG_defbootseloptpart, defbootselpart);
698: else
699: msg_display_add(MSG_defbootseloptdisk, defbootseldisk);
700: }
701:
702: void
703: edit_bootsel_entry(int ptn)
704: {
1.38 dsl 705:
1.33 dsl 706: if (part[ptn].mbrp_typ != 0)
707: msg_prompt(MSG_bootselitemname, mbs->mbrb_nametab[ptn],
708: mbs->mbrb_nametab[ptn], 8);
709: }
710:
711: void
712: edit_bootsel_timeout(void)
713: {
714: char tstr[8];
715: unsigned timo;
716:
717: do {
718: snprintf(tstr, 8, "%u", (10 * mbs->mbrb_timeo + 9) / 182);
719: msg_prompt(MSG_bootseltimeoutval, tstr, tstr, 8);
720: timo = (unsigned)atoi(tstr);
721: } while (timo > 3600);
722: mbs->mbrb_timeo = (u_int16_t)((timo * 182) / 10);
723: }
724:
725: void
726: edit_bootsel_default_ptn(int ptn)
727: {
728: int i;
729: int key = SCAN_1;
730:
731: if (mbs->mbrb_nametab[ptn][0] == 0 || part[ptn].mbrp_typ == 0)
732: return;
733: for (i = 0; i < ptn; i++)
734: if (mbs->mbrb_nametab[i][0] != 0 && part[i].mbrp_typ != 0)
735: key++;
736: mbs->mbrb_defkey = key;
737: defbootselpart = ptn;
738: }
739:
740: void
741: edit_bootsel_default_disk(int disk)
742: {
743:
744: mbs->mbrb_defkey = SCAN_F1 + disk;
745: defbootseldisk = disk;
746: }
1.34 dsl 747:
748: void
749: configure_bootsel(void)
750: {
751: struct mbr_partition *parts = &mbr.mbr_parts[0];
752: int i;
753: const char *name, *cp;
754:
755: mbs = &mbr.mbr_bootsel;
756:
757: /*
758: * Setup default labels for partitions, since if not done by user
759: * they don't get set and bootselector doesn't 'appear' when
760: * it's loaded.
761: */
1.36 dsl 762: for (i = 0; i < NMBRPART; i++) {
763: if (parts[i].mbrp_typ == 0 ||
764: parts[i].mbrp_typ == MBR_PTYPE_LNXSWAP ||
765: MBR_IS_EXTENDED(parts[i].mbrp_typ))
766: mbs->mbrb_nametab[i][0] = 0;
767: }
768:
1.34 dsl 769: for (i = 0; i < NMBRPART; i++) {
770: if (parts[i].mbrp_typ == MBR_PTYPE_NETBSD &&
771: mbs->mbrb_nametab[i][0] != 0)
772: goto labels_ok;
773: }
774:
775: for (i = 0; i < NMBRPART; i++) {
776: if (parts[i].mbrp_typ == 0 ||
777: parts[i].mbrp_typ == MBR_PTYPE_LNXSWAP ||
778: MBR_IS_EXTENDED(parts[i].mbrp_typ) ||
779: mbs->mbrb_nametab[i][0] != '\0')
780: continue;
781: /* Default to first word of partition name */
782: name = get_partname(i);
783: cp = strchr(name, ' ');
784: snprintf(mbs->mbrb_nametab[i], sizeof(mbs->mbrb_nametab[0]),
785: "%.*s", cp != NULL ? cp - name : 256, name);
786: }
787:
788: labels_ok:
1.37 dsl 789: process_menu(MENU_configbootsel, NULL);
1.34 dsl 790:
791: #if 0
792: /* The current bootselect code doesn't need this... */
793: mbs->mbrb_flags &= ~BFL_EXTINT13;
794: for (i = 0; i < NMBRPART; i++) {
795: if (parts[i].mbrp_typ != 0 &&
796: parts[i].mbrp_start >= (bcyl * bhead * bsec)) {
797: mbs->mbrb_flags |= BFL_EXTINT13;
798: break;
799: }
800: }
801: #endif
802: }
803:
1.33 dsl 804: #endif
CVSweb <webmaster@jp.NetBSD.org>