Home | History | Annotate | Download | only in chain
      1 /* ----------------------------------------------------------------------- *
      2  *
      3  *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
      4  *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
      5  *   Copyright 2010 Shao Miller
      6  *   Copyright 2010-2012 Michal Soltys
      7  *
      8  *   Permission is hereby granted, free of charge, to any person
      9  *   obtaining a copy of this software and associated documentation
     10  *   files (the "Software"), to deal in the Software without
     11  *   restriction, including without limitation the rights to use,
     12  *   copy, modify, merge, publish, distribute, sublicense, and/or
     13  *   sell copies of the Software, and to permit persons to whom
     14  *   the Software is furnished to do so, subject to the following
     15  *   conditions:
     16  *
     17  *   The above copyright notice and this permission notice shall
     18  *   be included in all copies or substantial portions of the Software.
     19  *
     20  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     21  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     22  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     23  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     24  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     25  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     26  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     27  *   OTHER DEALINGS IN THE SOFTWARE.
     28  *
     29  * ----------------------------------------------------------------------- */
     30 
     31 #include <com32.h>
     32 #include <fcntl.h>
     33 #include <stdint.h>
     34 #include <stdio.h>
     35 #include <errno.h>
     36 #include <unistd.h>
     37 #include <string.h>
     38 #include <fs.h>
     39 #include <syslinux/disk.h>
     40 #include <syslinux/pmapi.h>
     41 #include "utility.h"
     42 
     43 static const char *bpbtypes[] = {
     44     [0] =  "unknown",
     45     [1] =  "2.0",
     46     [2] =  "3.0",
     47     [3] =  "3.2",
     48     [4] =  "3.4",
     49     [5] =  "4.0",
     50     [6] =  "8.0 (NT+)",
     51     [7] =  "7.0",
     52     [8] =  "exFAT",
     53 };
     54 
     55 void wait_key(void)
     56 {
     57     int cnt;
     58     char junk;
     59 
     60     /* drain */
     61     do {
     62 	errno = 0;
     63 	cnt = read(0, &junk, 1);
     64     } while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
     65 
     66     /* wait */
     67     do {
     68 	errno = 0;
     69 	cnt = read(0, &junk, 1);
     70     } while (!cnt || (cnt < 0 && errno == EAGAIN));
     71 }
     72 
     73 int guid_is0(const struct guid *guid)
     74 {
     75     return
     76 	!(guid->data1 ||
     77 	  guid->data2 ||
     78 	  guid->data3 ||
     79 	  guid->data4);
     80 }
     81 
     82 /*
     83  * mode explanation:
     84  *
     85  * cnul - "strict" mode, never returning higher value than obtained from cbios
     86  * cadd - if the disk is larger than reported geometry /and/ if the geometry has
     87  *        less cylinders than 1024 - it means that the total size is somewhere
     88  *        between cs and cs+1; in this particular case, we bump the cs to be able
     89  *        to return matching chs triplet
     90  * cmax - assume we can use any cylinder value
     91  *
     92  * by default cadd seems most reasonable, giving consistent results with e.g.
     93  * sfdisk's behavior
     94  */
     95 void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode)
     96 {
     97     uint32_t c, h, s, t;
     98     uint32_t cs, hs, ss;
     99 
    100     /*
    101      * Not much reason here, but if we have no valid CHS geometry, we assume
    102      * "typical" ones to have something to return.
    103      */
    104     if (di->cbios) {
    105 	cs = di->cyl;
    106 	hs = di->head;
    107 	ss = di->spt;
    108 	if (mode == L2C_CADD) {
    109 	    if (cs < 1024 && di->lbacnt > cs*hs*ss)
    110 		cs++;
    111 	} else if (mode == L2C_CMAX)
    112 	    cs = 1024;
    113     } else {
    114 	if (di->disk & 0x80) {
    115 	    cs = 1024;
    116 	    hs = 255;
    117 	    ss = 63;
    118 	} else {
    119 	    cs = 80;
    120 	    hs = 2;
    121 	    ss = 18;
    122 	}
    123     }
    124 
    125     if (lba >= cs*hs*ss) {
    126 	s = ss;
    127 	h = hs - 1;
    128 	c = cs - 1;
    129     } else {
    130 	s = (lba % ss) + 1;
    131 	t = lba / ss;
    132 	h = t % hs;
    133 	c = t / hs;
    134     }
    135 
    136     (*dst)[0] = h;
    137     (*dst)[1] = s | ((c & 0x300) >> 2);
    138     (*dst)[2] = c;
    139 }
    140 
    141 uint32_t get_file_lba(const char *filename)
    142 {
    143     struct com32_filedata fd;
    144     uint32_t lba = 0;
    145     int size = 65536;
    146     char *buf;
    147 
    148     buf = lmalloc(size);
    149     if (!buf)
    150 	return 0;
    151 
    152     /* Put the filename in the bounce buffer */
    153     strlcpy(buf, filename, size);
    154 
    155     if (open_file(buf, O_RDONLY, &fd) <= 0) {
    156 	goto fail;		/* Filename not found */
    157     }
    158 
    159     /* Since the first member is the LBA, we simply cast */
    160     lba = *((uint32_t *) MK_PTR(0, fd.handle));
    161 
    162     /* Call comapi_close() to free the structure */
    163     close_file(fd.handle);
    164 
    165 fail:
    166     lfree(buf);
    167     return lba;
    168 }
    169 
    170 /* drive offset detection */
    171 int drvoff_detect(int type)
    172 {
    173     if (bpbV40 <= type && type <= bpbVNT) {
    174 	return 0x24;
    175     } else if (type == bpbV70) {
    176 	return 0x40;
    177     } else if (type == bpbEXF) {
    178 	return 0x6F;
    179     }
    180 
    181     return -1;
    182 }
    183 
    184 /*
    185  * heuristics could certainly be improved
    186  */
    187 int bpb_detect(const uint8_t *sec, const char *tag)
    188 {
    189     int a, b, c, jmp = -1, rev = 0;
    190 
    191     /* exFAT mess first (media descriptor is 0 here) */
    192     if (!memcmp(sec + 0x03, "EXFAT   ", 8)) {
    193 	rev = bpbEXF;
    194 	goto out;
    195     }
    196 
    197     /* media descriptor check */
    198     if ((sec[0x15] & 0xF0) != 0xF0)
    199 	goto out;
    200 
    201     if (sec[0] == 0xEB)	/* jump short */
    202 	jmp = 2 + *(int8_t *)(sec + 1);
    203     else if (sec[0] == 0xE9) /* jump near */
    204 	jmp = 3 + *(int16_t *)(sec + 1);
    205 
    206     if (jmp < 0)    /* no boot code at all ? */
    207 	goto nocode;
    208 
    209     /* sanity */
    210     if (jmp < 0x18 || jmp > 0x1F0)
    211 	goto out;
    212 
    213     /* detect by jump */
    214     if (jmp >= 0x18 && jmp < 0x1E)
    215 	rev = bpbV20;
    216     else if (jmp >= 0x1E && jmp < 0x20)
    217 	rev = bpbV30;
    218     else if (jmp >= 0x20 && jmp < 0x24)
    219 	rev = bpbV32;
    220     else if (jmp >= 0x24 && jmp < 0x46)
    221 	rev = bpbV34;
    222 
    223     /* TODO: some better V2 - V3.4 checks ? */
    224 
    225     if (rev)
    226 	goto out;
    227     /*
    228      * BPB info:
    229      * 2.0 ==       0x0B - 0x17
    230      * 3.0 == 2.0 + 0x18 - 0x1D
    231      * 3.2 == 3.0 + 0x1E - 0x1F
    232      * 3.4 ==!2.0 + 0x18 - 0x23
    233      * 4.0 == 3.4 + 0x24 - 0x45
    234      *  NT ==~3.4 + 0x24 - 0x53
    235      * 7.0 == 3.4 + 0x24 - 0x59
    236      */
    237 
    238 nocode:
    239     a = memcmp(sec + 0x03, "NTFS", 4);
    240     b = memcmp(sec + 0x36, "FAT", 3);
    241     c = memcmp(sec + 0x52, "FAT", 3);	/* ext. DOS 7+ bs */
    242 
    243     if ((sec[0x26] & 0xFE) == 0x28 && !b) {
    244 	rev = bpbV40;
    245     } else if (sec[0x26] == 0x80 && !a) {
    246 	rev = bpbVNT;
    247     } else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
    248 	rev = bpbV70;
    249     }
    250 
    251 out:
    252     printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]);
    253     return rev;
    254 }
    255 
    256 /* vim: set ts=8 sts=4 sw=4 noet: */
    257