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