summaryrefslogtreecommitdiff
path: root/com32/chain/utility.c
diff options
context:
space:
mode:
Diffstat (limited to 'com32/chain/utility.c')
-rw-r--r--com32/chain/utility.c136
1 files changed, 89 insertions, 47 deletions
diff --git a/com32/chain/utility.c b/com32/chain/utility.c
index fb59551b..b17997f7 100644
--- a/com32/chain/utility.c
+++ b/com32/chain/utility.c
@@ -1,10 +1,43 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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[] = {
@@ -16,18 +49,9 @@ static const char *bpbtypes[] = {
[5] = "4.0",
[6] = "8.0 (NT+)",
[7] = "7.0",
+ [8] = "exFAT",
};
-void error(const char *msg)
-{
- fputs(msg, stderr);
-}
-
-int guid_is0(const struct guid *guid)
-{
- return !*(const uint64_t *)guid && !*((const uint64_t *)guid + 1);
-}
-
void wait_key(void)
{
int cnt;
@@ -46,7 +70,29 @@ void wait_key(void)
} while (!cnt || (cnt < 0 && errno == EAGAIN));
}
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode)
+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;
@@ -59,9 +105,10 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
cs = di->cyl;
hs = di->head;
ss = di->spt;
- if (mode == l2c_cadd && cs < 1024 && di->lbacnt > cs*hs*ss)
- cs++;
- else if (mode == l2c_cmax)
+ 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) {
@@ -80,8 +127,8 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
h = hs - 1;
c = cs - 1;
} else {
- s = ((uint32_t)lba % ss) + 1;
- t = (uint32_t)lba / ss;
+ s = (lba % ss) + 1;
+ t = lba / ss;
h = t % hs;
c = t / hs;
}
@@ -93,54 +140,43 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
uint32_t get_file_lba(const char *filename)
{
- com32sys_t inregs;
- uint32_t lba;
+ struct com32_filedata fd;
+ uint32_t lba = 0;
+ int size = 65536;
+ char *buf;
- /* Start with clean registers */
- memset(&inregs, 0, sizeof(com32sys_t));
+ buf = lmalloc(size);
+ if (!buf)
+ return 0;
/* Put the filename in the bounce buffer */
- strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
-
- /* Call comapi_open() which returns a structure pointer in SI
- * to a structure whose first member happens to be the LBA.
- */
- inregs.eax.w[0] = 0x0006;
- inregs.esi.w[0] = OFFS(__com32.cs_bounce);
- inregs.es = SEG(__com32.cs_bounce);
- __com32.cs_intcall(0x22, &inregs, &inregs);
+ strlcpy(buf, filename, size);
- if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) {
- return 0; /* Filename not found */
+ 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(inregs.ds, inregs.esi.w[0]));
-
- /* Clean the registers for the next call */
- memset(&inregs, 0, sizeof(com32sys_t));
-
- /* Put the filename in the bounce buffer */
- strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
+ lba = *((uint32_t *) MK_PTR(0, fd.handle));
/* Call comapi_close() to free the structure */
- inregs.eax.w[0] = 0x0008;
- inregs.esi.w[0] = OFFS(__com32.cs_bounce);
- inregs.es = SEG(__com32.cs_bounce);
- __com32.cs_intcall(0x22, &inregs, &inregs);
+ close_file(fd.handle);
+fail:
+ lfree(buf);
return lba;
}
/* drive offset detection */
-int drvoff_detect(int type, unsigned int *off)
+int drvoff_detect(int type)
{
if (bpbV40 <= type && type <= bpbVNT) {
- *off = 0x24;
+ return 0x24;
} else if (type == bpbV70) {
- *off = 0x40;
- } else
- return 0;
+ return 0x40;
+ } else if (type == bpbEXF) {
+ return 0x6F;
+ }
return -1;
}
@@ -152,6 +188,12 @@ 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;