257 lines
6.1 KiB
C
257 lines
6.1 KiB
C
/* ----------------------------------------------------------------------- *
|
|
*
|
|
* Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
|
|
* Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
|
|
* Copyright 2010 Shao Miller
|
|
* Copyright 2010-2012 Michal Soltys
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom
|
|
* the Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall
|
|
* be included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
#include <com32.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <fs.h>
|
|
#include <syslinux/disk.h>
|
|
#include <syslinux/pmapi.h>
|
|
#include "utility.h"
|
|
|
|
static const char *bpbtypes[] = {
|
|
[0] = "unknown",
|
|
[1] = "2.0",
|
|
[2] = "3.0",
|
|
[3] = "3.2",
|
|
[4] = "3.4",
|
|
[5] = "4.0",
|
|
[6] = "8.0 (NT+)",
|
|
[7] = "7.0",
|
|
[8] = "exFAT",
|
|
};
|
|
|
|
void wait_key(void)
|
|
{
|
|
int cnt;
|
|
char junk;
|
|
|
|
/* drain */
|
|
do {
|
|
errno = 0;
|
|
cnt = read(0, &junk, 1);
|
|
} while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
|
|
|
|
/* wait */
|
|
do {
|
|
errno = 0;
|
|
cnt = read(0, &junk, 1);
|
|
} while (!cnt || (cnt < 0 && errno == EAGAIN));
|
|
}
|
|
|
|
int guid_is0(const struct guid *guid)
|
|
{
|
|
return
|
|
!(guid->data1 ||
|
|
guid->data2 ||
|
|
guid->data3 ||
|
|
guid->data4);
|
|
}
|
|
|
|
/*
|
|
* mode explanation:
|
|
*
|
|
* cnul - "strict" mode, never returning higher value than obtained from cbios
|
|
* cadd - if the disk is larger than reported geometry /and/ if the geometry has
|
|
* less cylinders than 1024 - it means that the total size is somewhere
|
|
* between cs and cs+1; in this particular case, we bump the cs to be able
|
|
* to return matching chs triplet
|
|
* cmax - assume we can use any cylinder value
|
|
*
|
|
* by default cadd seems most reasonable, giving consistent results with e.g.
|
|
* sfdisk's behavior
|
|
*/
|
|
void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode)
|
|
{
|
|
uint32_t c, h, s, t;
|
|
uint32_t cs, hs, ss;
|
|
|
|
/*
|
|
* Not much reason here, but if we have no valid CHS geometry, we assume
|
|
* "typical" ones to have something to return.
|
|
*/
|
|
if (di->cbios) {
|
|
cs = di->cyl;
|
|
hs = di->head;
|
|
ss = di->spt;
|
|
if (mode == L2C_CADD) {
|
|
if (cs < 1024 && di->lbacnt > cs*hs*ss)
|
|
cs++;
|
|
} else if (mode == L2C_CMAX)
|
|
cs = 1024;
|
|
} else {
|
|
if (di->disk & 0x80) {
|
|
cs = 1024;
|
|
hs = 255;
|
|
ss = 63;
|
|
} else {
|
|
cs = 80;
|
|
hs = 2;
|
|
ss = 18;
|
|
}
|
|
}
|
|
|
|
if (lba >= cs*hs*ss) {
|
|
s = ss;
|
|
h = hs - 1;
|
|
c = cs - 1;
|
|
} else {
|
|
s = (lba % ss) + 1;
|
|
t = lba / ss;
|
|
h = t % hs;
|
|
c = t / hs;
|
|
}
|
|
|
|
(*dst)[0] = h;
|
|
(*dst)[1] = s | ((c & 0x300) >> 2);
|
|
(*dst)[2] = c;
|
|
}
|
|
|
|
uint32_t get_file_lba(const char *filename)
|
|
{
|
|
struct com32_filedata fd;
|
|
uint32_t lba = 0;
|
|
int size = 65536;
|
|
char *buf;
|
|
|
|
buf = lmalloc(size);
|
|
if (!buf)
|
|
return 0;
|
|
|
|
/* Put the filename in the bounce buffer */
|
|
strlcpy(buf, filename, size);
|
|
|
|
if (open_file(buf, O_RDONLY, &fd) <= 0) {
|
|
goto fail; /* Filename not found */
|
|
}
|
|
|
|
/* Since the first member is the LBA, we simply cast */
|
|
lba = *((uint32_t *) MK_PTR(0, fd.handle));
|
|
|
|
/* Call comapi_close() to free the structure */
|
|
close_file(fd.handle);
|
|
|
|
fail:
|
|
lfree(buf);
|
|
return lba;
|
|
}
|
|
|
|
/* drive offset detection */
|
|
int drvoff_detect(int type)
|
|
{
|
|
if (bpbV40 <= type && type <= bpbVNT) {
|
|
return 0x24;
|
|
} else if (type == bpbV70) {
|
|
return 0x40;
|
|
} else if (type == bpbEXF) {
|
|
return 0x6F;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* heuristics could certainly be improved
|
|
*/
|
|
int bpb_detect(const uint8_t *sec, const char *tag)
|
|
{
|
|
int a, b, c, jmp = -1, rev = 0;
|
|
|
|
/* exFAT mess first (media descriptor is 0 here) */
|
|
if (!memcmp(sec + 0x03, "EXFAT ", 8)) {
|
|
rev = bpbEXF;
|
|
goto out;
|
|
}
|
|
|
|
/* media descriptor check */
|
|
if ((sec[0x15] & 0xF0) != 0xF0)
|
|
goto out;
|
|
|
|
if (sec[0] == 0xEB) /* jump short */
|
|
jmp = 2 + *(int8_t *)(sec + 1);
|
|
else if (sec[0] == 0xE9) /* jump near */
|
|
jmp = 3 + *(int16_t *)(sec + 1);
|
|
|
|
if (jmp < 0) /* no boot code at all ? */
|
|
goto nocode;
|
|
|
|
/* sanity */
|
|
if (jmp < 0x18 || jmp > 0x1F0)
|
|
goto out;
|
|
|
|
/* detect by jump */
|
|
if (jmp >= 0x18 && jmp < 0x1E)
|
|
rev = bpbV20;
|
|
else if (jmp >= 0x1E && jmp < 0x20)
|
|
rev = bpbV30;
|
|
else if (jmp >= 0x20 && jmp < 0x24)
|
|
rev = bpbV32;
|
|
else if (jmp >= 0x24 && jmp < 0x46)
|
|
rev = bpbV34;
|
|
|
|
/* TODO: some better V2 - V3.4 checks ? */
|
|
|
|
if (rev)
|
|
goto out;
|
|
/*
|
|
* BPB info:
|
|
* 2.0 == 0x0B - 0x17
|
|
* 3.0 == 2.0 + 0x18 - 0x1D
|
|
* 3.2 == 3.0 + 0x1E - 0x1F
|
|
* 3.4 ==!2.0 + 0x18 - 0x23
|
|
* 4.0 == 3.4 + 0x24 - 0x45
|
|
* NT ==~3.4 + 0x24 - 0x53
|
|
* 7.0 == 3.4 + 0x24 - 0x59
|
|
*/
|
|
|
|
nocode:
|
|
a = memcmp(sec + 0x03, "NTFS", 4);
|
|
b = memcmp(sec + 0x36, "FAT", 3);
|
|
c = memcmp(sec + 0x52, "FAT", 3); /* ext. DOS 7+ bs */
|
|
|
|
if ((sec[0x26] & 0xFE) == 0x28 && !b) {
|
|
rev = bpbV40;
|
|
} else if (sec[0x26] == 0x80 && !a) {
|
|
rev = bpbVNT;
|
|
} else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
|
|
rev = bpbV70;
|
|
}
|
|
|
|
out:
|
|
printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]);
|
|
return rev;
|
|
}
|
|
|
|
/* vim: set ts=8 sts=4 sw=4 noet: */
|