summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErwan Velu <erwan.velu@free.fr>2009-11-20 23:14:00 +0100
committerErwan Velu <erwan.velu@free.fr>2009-11-20 23:14:00 +0100
commit900d7a87216346fedc7af7425ed711b6979fec4b (patch)
treee7b03aa43a9e43a2775cd5cde36e6ea64980b8c1
parentb417dc2763b6009a3b823f229b931f1847982826 (diff)
parenta0dae108231cdd929aff1f6551fcb70c806c0f99 (diff)
downloadsyslinux-900d7a87216346fedc7af7425ed711b6979fec4b.tar.gz
Merge remote branch 'hpa/master'
-rw-r--r--NEWS5
-rw-r--r--com32/include/dprintf.h22
-rw-r--r--com32/lib/Makefile2
-rw-r--r--com32/lib/dprintf.c19
-rw-r--r--com32/lib/sys/open.c3
-rw-r--r--com32/lib/vdprintf.c46
-rw-r--r--com32/mboot/Makefile2
-rw-r--r--com32/mboot/initvesa.c226
-rw-r--r--com32/mboot/map.c32
-rw-r--r--com32/mboot/mboot.c7
-rw-r--r--com32/mboot/mboot.h6
-rw-r--r--com32/mboot/vesa.h100
-rw-r--r--com32/menu/menu.h3
-rw-r--r--com32/menu/readconfig.c4
-rw-r--r--doc/memdisk.txt1
-rw-r--r--dos/Makefile8
-rw-r--r--dos/com16.ld5
-rw-r--r--dos/int2526.S76
-rw-r--r--dos/mystuff.h10
-rw-r--r--dos/syslinux.c218
-rw-r--r--memdisk/Makefile10
-rw-r--r--memdisk/bda.h56
-rw-r--r--memdisk/dskprobe.c114
-rw-r--r--memdisk/dskprobe.h21
-rw-r--r--memdisk/eltorito.c58
-rw-r--r--memdisk/eltorito.h83
-rw-r--r--memdisk/memdisk.inc87
-rw-r--r--memdisk/memdisk_chs.asm3
-rw-r--r--memdisk/memdisk_chs_512.asm5
-rw-r--r--memdisk/memdisk_edd.asm3
-rw-r--r--memdisk/memdisk_edd_512.asm5
-rw-r--r--memdisk/memdisk_iso_2048.asm5
-rw-r--r--memdisk/memdisk_iso_512.asm5
-rw-r--r--memdisk/setup.c278
-rw-r--r--utils/isohybrid.in4
-rw-r--r--version2
36 files changed, 1342 insertions, 192 deletions
diff --git a/NEWS b/NEWS
index c934a3e3..ed606cab 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,11 @@ Starting with 1.47, changes marked with SYSLINUX, PXELINUX, ISOLINUX
or EXTLINUX apply to that specific program only; other changes apply
to all derivatives.
+Changes in 3.84:
+ * SYSLINUX: make the DOS installer work for MS-DOS 7.x/8.x
+ (Win9x/ME) again.
+ * HDT: updated to version 0.3.5.
+
Changes in 3.83:
* PXELINUX: clear memory before handing over to a chainloaded
NBP. This may help avoid a bug in Windows RIS.
diff --git a/com32/include/dprintf.h b/com32/include/dprintf.h
new file mode 100644
index 00000000..30a21ada
--- /dev/null
+++ b/com32/include/dprintf.h
@@ -0,0 +1,22 @@
+/*
+ * dprintf.h
+ */
+
+#ifndef _DPRINTF_H
+#define _DPRINTF_H
+
+#ifdef DEBUG
+
+#include <stdio.h>
+
+void dprintf(const char *, ...);
+void vdprintf(const char *, va_list);
+
+#else
+
+#define dprintf(fmt, ...) ((void)(0))
+#define vdprintf(fmt, ap) ((void)(0))
+
+#endif /* DEBUG */
+
+#endif /* _DPRINTF_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 3a9eafd6..f1e2680f 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -27,6 +27,8 @@ LIBOBJS = \
asprintf.o vasprintf.o strlcpy.o strlcat.o \
vsscanf.o zalloc.o \
\
+ dprintf.o vdprintf.o \
+ \
opendir.o readdir.o closedir.o getcwd.o chdir.o fdopendir.o \
\
libgcc/__ashldi3.o libgcc/__udivdi3.o \
diff --git a/com32/lib/dprintf.c b/com32/lib/dprintf.c
new file mode 100644
index 00000000..900c0a47
--- /dev/null
+++ b/com32/lib/dprintf.c
@@ -0,0 +1,19 @@
+/*
+ * dprintf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#undef DEBUG
+#define DEBUG 1
+#include <dprintf.h>
+
+void dprintf(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vdprintf(format, ap);
+ va_end(ap);
+}
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
index aabbec21..aac5e6f4 100644
--- a/com32/lib/sys/open.c
+++ b/com32/lib/sys/open.c
@@ -72,13 +72,14 @@ int open(const char *pathname, int flags, ...)
__com32.cs_intcall(0x22, &regs, &regs);
if ((regs.eflags.l & EFLAGS_CF) || regs.esi.w[0] == 0) {
+ close(fd);
errno = ENOENT;
return -1;
}
{
uint16_t blklg2;
-asm("bsrw %1,%0": "=r"(blklg2):"rm"(regs.ecx.w[0]));
+ asm("bsrw %1,%0" : "=r" (blklg2) : "rm" (regs.ecx.w[0]));
fp->i.blocklg2 = blklg2;
}
fp->i.length = regs.eax.l;
diff --git a/com32/lib/vdprintf.c b/com32/lib/vdprintf.c
new file mode 100644
index 00000000..ea9e0488
--- /dev/null
+++ b/com32/lib/vdprintf.c
@@ -0,0 +1,46 @@
+/*
+ * vdprintf.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/io.h>
+#include <sys/cpu.h>
+
+#undef DEBUG
+#define DEBUG 1
+#include <dprintf.h>
+
+#define BUFFER_SIZE 32768
+
+static const uint16_t debug_base = 0x03f8; /* I/O base address */
+
+void vdprintf(const char *format, va_list ap)
+{
+ int rv;
+ char buffer[BUFFER_SIZE];
+ char *p;
+
+ rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
+
+ if (rv < 0)
+ return;
+
+ if (rv > BUFFER_SIZE - 1)
+ rv = BUFFER_SIZE - 1;
+
+ /*
+ * This unconditionally outputs to a serial port at 0x3f8 regardless of
+ * if one is enabled or not (this means we don't have to enable the real
+ * serial console and therefore get conflicting output.)
+ */
+ p = buffer;
+ while (rv--) {
+ while ((inb(debug_base+5) & 0x20) == 0)
+ cpu_relax();
+ outb(*p++, debug_base);
+ }
+}
diff --git a/com32/mboot/Makefile b/com32/mboot/Makefile
index a6902716..c1ac76fb 100644
--- a/com32/mboot/Makefile
+++ b/com32/mboot/Makefile
@@ -24,7 +24,7 @@ LNXLIBS = ../libutil/libutil_lnx.a
MODULES = mboot.c32
TESTFILES =
-OBJS = mboot.o map.o mem.o apm.o solaris.o
+OBJS = mboot.o map.o mem.o initvesa.o apm.o solaris.o
all: $(MODULES) $(TESTFILES)
diff --git a/com32/mboot/initvesa.c b/com32/mboot/initvesa.c
new file mode 100644
index 00000000..cf2707df
--- /dev/null
+++ b/com32/mboot/initvesa.c
@@ -0,0 +1,226 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * initvesa.c
+ *
+ * Query the VESA BIOS and select a 640x480x32 mode with local mapping
+ * support, if one exists.
+ */
+
+#include <inttypes.h>
+#include <com32.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "vesa.h"
+#include "mboot.h"
+
+struct vesa_info vesa_info;
+
+void set_graphics_mode(const struct multiboot_header *mbh,
+ struct multiboot_info *mbi)
+{
+ com32sys_t rm;
+ uint16_t mode, bestmode, *mode_ptr;
+ struct vesa_general_info *gi;
+ struct vesa_mode_info *mi;
+ int pxf, bestpxf;
+ int wantx, wanty;
+ int err, besterr;
+ bool better;
+ addr_t viaddr;
+
+ /* Only do this if requested by the OS image */
+ if (!(mbh->flags & MULTIBOOT_VIDEO_MODE) || mbh->mode_type != 0)
+ return;
+
+ /* Allocate space in the bounce buffer for these structures */
+ gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
+ mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+
+ memset(&rm, 0, sizeof rm);
+ memset(gi, 0, sizeof *gi);
+
+ gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
+ rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
+ rm.edi.w[0] = OFFS(gi);
+ rm.es = SEG(gi);
+ __intcall(0x10, &rm, &rm);
+
+ if (rm.eax.w[0] != 0x004F)
+ return; /* Function call failed */
+ if (gi->signature != VESA_MAGIC)
+ return; /* No magic */
+ if (gi->version < 0x0102)
+ return; /* VESA 1.2+ required */
+
+ memcpy(&vesa_info.gi, gi, sizeof *gi);
+
+ /* Search for a suitable mode with a suitable color and memory model... */
+
+ mode_ptr = GET_PTR(gi->video_mode_ptr);
+ bestmode = 0;
+ bestpxf = 0;
+ wantx = mbh->width ? mbh->width : 0xffff;
+ wanty = mbh->height ? mbh->height : 0xffff;
+ besterr = wantx + wanty;
+
+ while ((mode = *mode_ptr++) != 0xFFFF) {
+ mode &= 0x1FF; /* The rest are attributes of sorts */
+
+ memset(mi, 0, sizeof *mi);
+ rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */
+ rm.ecx.w[0] = mode;
+ rm.edi.w[0] = OFFS(mi);
+ rm.es = SEG(mi);
+ __intcall(0x10, &rm, &rm);
+
+ /* Must be a supported mode */
+ if (rm.eax.w[0] != 0x004f)
+ continue;
+
+ /* Must be an LFB color graphics mode supported by the hardware.
+
+ The bits tested are:
+ 7 - linear frame buffer
+ 4 - graphics mode
+ 3 - color mode
+ 1 - mode information available (mandatory in VBE 1.2+)
+ 0 - mode supported by hardware
+ */
+ if ((mi->mode_attr & 0x009b) != 0x009b)
+ continue;
+
+ /* We don't support multibank (interlaced memory) modes */
+ /*
+ * Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
+ * specification which states that banks == 1 for unbanked modes;
+ * fortunately it does report bank_size == 0 for those.
+ */
+ if (mi->banks > 1 && mi->bank_size)
+ continue;
+
+ /* Must either be a packed-pixel mode or a direct color mode
+ (depending on VESA version ); must be a supported pixel format */
+
+ if (mi->bpp == 32 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
+ mi->bpos == 0)))
+ pxf = 32;
+ else if (mi->bpp == 24 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
+ mi->bpos == 0)))
+ pxf = 24;
+ else if (mi->bpp == 16 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 &&
+ mi->bpos == 0)))
+ pxf = 16;
+ else if (mi->bpp == 15 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 10 && mi->gpos == 5 &&
+ mi->bpos == 0)))
+ pxf = 15;
+ else
+ continue;
+
+ better = false;
+ err = abs(mi->h_res - wantx) + abs(mi->v_res - wanty);
+
+#define IS_GOOD(mi, bestx, besty) \
+ ((mi)->h_res >= (bestx) && (mi)->v_res >= (besty))
+
+ if (!bestpxf)
+ better = true;
+ else if (!IS_GOOD(&vesa_info.mi, wantx, wanty) &&
+ IS_GOOD(mi, wantx, wanty))
+ /* This matches criteria, which the previous one didn't */
+ better = true;
+ else if (IS_GOOD(&vesa_info.mi, wantx, wanty) &&
+ !IS_GOOD(mi, wantx, wanty))
+ /* This doesn't match criteria, and the previous one did */
+ better = false;
+ else if (err < besterr)
+ better = true;
+ else if (err == besterr && (pxf == (int)mbh->depth || pxf > bestpxf))
+ better = true;
+
+ if (better) {
+ bestmode = mode;
+ bestpxf = pxf;
+ memcpy(&vesa_info.mi, mi, sizeof *mi);
+ }
+ }
+
+ if (!bestpxf)
+ return; /* No mode found */
+
+ mi = &vesa_info.mi;
+ mode = bestmode;
+
+ /* Now set video mode */
+ rm.eax.w[0] = 0x4F02; /* Set SVGA video mode */
+ mode |= 0x4000; /* Request linear framebuffer */
+ rm.ebx.w[0] = mode;
+ __intcall(0x10, &rm, &rm);
+ if (rm.eax.w[0] != 0x004F)
+ return; /* Failed to set mode */
+
+ mbi->flags |= MB_INFO_VIDEO_INFO;
+ mbi->vbe_mode = mode;
+ viaddr = map_data(&vesa_info, sizeof vesa_info, 4, 0);
+ mbi->vbe_control_info = viaddr + offsetof(struct vesa_info, gi);
+ mbi->vbe_mode_info = viaddr + offsetof(struct vesa_info, mi);
+
+ /* Get the VBE 2.x PM entry point if supported */
+ rm.eax.w[0] = 0x4F0A;
+ rm.ebx.w[0] = 0;
+ __intcall(0x10, &rm, &rm);
+ if (rm.eax.w[0] == 0x004F) {
+ mbi->vbe_interface_seg = rm.es;
+ mbi->vbe_interface_off = rm.edi.w[0];
+ mbi->vbe_interface_len = rm.ecx.w[0];
+ }
+
+ /* Tell syslinux we changed video mode */
+ rm.eax.w[0] = 0x0017; /* Report video mode change */
+ /* In theory this should be:
+
+ rm.ebx.w[0] = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
+
+ However, that would assume all systems that claim to handle text
+ output in VESA modes actually do that... */
+ rm.ebx.w[0] = 0x000f;
+ rm.ecx.w[0] = vesa_info.mi.h_res;
+ rm.edx.w[0] = vesa_info.mi.v_res;
+ __intcall(0x22, &rm, NULL);
+}
diff --git a/com32/mboot/map.c b/com32/mboot/map.c
index 887776fe..a32f9b3b 100644
--- a/com32/mboot/map.c
+++ b/com32/mboot/map.c
@@ -36,7 +36,6 @@
static struct syslinux_movelist *ml = NULL;
static struct syslinux_memmap *mmap = NULL, *amap = NULL;
-static struct multiboot_header *mbh;
static addr_t mboot_high_water_mark = 0x100000;
/*
@@ -100,8 +99,9 @@ int init_map(void)
return 0;
}
-int map_image(void *ptr, size_t len)
+struct multiboot_header *map_image(void *ptr, size_t len)
{
+ struct multiboot_header *mbh;
int mbh_len;
char *cptr = ptr;
Elf32_Ehdr *eh = ptr;
@@ -134,10 +134,10 @@ int map_image(void *ptr, size_t len)
}
if (mbh_len) {
- bad_flags = mbh->flags & (MULTIBOOT_UNSUPPORTED | MULTIBOOT_VIDEO_MODE);
+ bad_flags = mbh->flags & MULTIBOOT_UNSUPPORTED;
if (bad_flags) {
printf("Unsupported Multiboot flags set: %#x\n", bad_flags);
- return -1;
+ return NULL;
}
}
@@ -187,13 +187,13 @@ int map_image(void *ptr, size_t len)
printf
("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
addr, msize);
- return -1; /* Memory region unavailable */
+ return NULL; /* Memory region unavailable */
}
/* Mark this region as allocated in the available map */
if (syslinux_add_memmap(&amap, addr, msize, SMT_ALLOC)) {
error("Overlapping segments found in ELF header\n");
- return -1;
+ return NULL;
}
if (ph->p_filesz) {
@@ -201,7 +201,7 @@ int map_image(void *ptr, size_t len)
if (syslinux_add_movelist
(&ml, addr, (addr_t) cptr + ph->p_offset, dsize)) {
error("Failed to map PHDR data\n");
- return -1;
+ return NULL;
}
}
if (msize > dsize) {
@@ -209,7 +209,7 @@ int map_image(void *ptr, size_t len)
if (syslinux_add_memmap
(&mmap, addr + dsize, msize - dsize, SMT_ZERO)) {
error("Failed to map PHDR zero region\n");
- return -1;
+ return NULL;
}
}
if (addr + msize > mboot_high_water_mark)
@@ -235,7 +235,7 @@ int map_image(void *ptr, size_t len)
addr = map_data(sh, len, 4096, MAP_HIGH | MAP_NOPAD);
if (!addr) {
error("Failed to map symbol table\n");
- return -1;
+ return NULL;
}
mbinfo.flags |= MB_INFO_ELF_SHDR;
@@ -257,7 +257,7 @@ int map_image(void *ptr, size_t len)
align, MAP_HIGH);
if (!addr) {
error("Failed to map symbol section\n");
- return -1;
+ return NULL;
}
sh[i].sh_addr = addr;
}
@@ -279,34 +279,34 @@ int map_image(void *ptr, size_t len)
!= SMT_FREE) {
printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
mbh->load_addr, data_len + bss_len);
- return -1; /* Memory region unavailable */
+ return NULL; /* Memory region unavailable */
}
if (syslinux_add_memmap(&amap, mbh->load_addr,
data_len + bss_len, SMT_ALLOC)) {
error("Failed to claim a.out address space!\n");
- return -1;
+ return NULL;
}
if (data_len)
if (syslinux_add_movelist(&ml, mbh->load_addr, (addr_t) data_ptr,
data_len)) {
error("Failed to map a.out data\n");
- return -1;
+ return NULL;
}
if (bss_len)
if (syslinux_add_memmap
(&mmap, mbh->load_end_addr, bss_len, SMT_ZERO)) {
error("Failed to map a.out bss\n");
- return -1;
+ return NULL;
}
if (mbh->bss_end_addr > mboot_high_water_mark)
mboot_high_water_mark = mbh->bss_end_addr;
} else {
error
("Invalid Multiboot image: neither ELF header nor a.out kludge found\n");
- return -1;
+ return NULL;
}
- return 0;
+ return mbh;
}
/*
diff --git a/com32/mboot/mboot.c b/com32/mboot/mboot.c
index e7bb8dbb..8425e068 100644
--- a/com32/mboot/mboot.c
+++ b/com32/mboot/mboot.c
@@ -152,6 +152,7 @@ int main(int argc, char *argv[])
{
int nmodules;
struct module_data *modules;
+ struct multiboot_header *mbh;
bool keeppxe = false;
openconsole(&dev_null_r, &dev_stdcon_w);
@@ -193,7 +194,8 @@ int main(int argc, char *argv[])
* Map the primary image. This should be done before mapping anything
* else, since it will have fixed address requirements.
*/
- if (map_image(modules[0].data, modules[0].len))
+ mbh = map_image(modules[0].data, modules[0].len);
+ if (!mbh)
return 1;
/* Map the mbinfo structure */
@@ -223,6 +225,9 @@ int main(int argc, char *argv[])
if (opt.solaris)
mboot_solaris_dhcp_hack();
+ /* Set the graphics mode if requested */
+ set_graphics_mode(mbh, &mbinfo);
+
/* Run it */
mboot_run(keeppxe ? 3 : 0);
error("mboot.c32: boot failed\n");
diff --git a/com32/mboot/mboot.h b/com32/mboot/mboot.h
index e5786206..993b31a8 100644
--- a/com32/mboot/mboot.h
+++ b/com32/mboot/mboot.h
@@ -79,7 +79,7 @@ extern struct my_options {
#define MAP_NOPAD 2
addr_t map_data(const void *data, size_t len, size_t align, int flags);
addr_t map_string(const char *string);
-int map_image(void *ptr, size_t len);
+struct multiboot_header *map_image(void *ptr, size_t len);
void mboot_run(int bootflags);
int init_map(void);
@@ -92,4 +92,8 @@ void mboot_apm(void);
/* solaris.c */
void mboot_solaris_dhcp_hack(void);
+/* initvesa.c */
+void set_graphics_mode(const struct multiboot_header *mbh,
+ struct multiboot_info *mbi);
+
#endif /* MBOOT_H */
diff --git a/com32/mboot/vesa.h b/com32/mboot/vesa.h
new file mode 100644
index 00000000..ecc084aa
--- /dev/null
+++ b/com32/mboot/vesa.h
@@ -0,0 +1,100 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef LIB_SYS_VESA_H
+#define LIB_SYS_VESA_H
+
+#include <inttypes.h>
+#include <com32.h>
+
+/* VESA General Information table */
+struct vesa_general_info {
+ uint32_t signature; /* Magic number = "VESA" */
+ uint16_t version;
+ far_ptr_t vendor_string;
+ uint8_t capabilities[4];
+ far_ptr_t video_mode_ptr;
+ uint16_t total_memory;
+
+ uint16_t oem_software_rev;
+ far_ptr_t oem_vendor_name_ptr;
+ far_ptr_t oem_product_name_ptr;
+ far_ptr_t oem_product_rev_ptr;
+
+ uint8_t reserved[222];
+ uint8_t oem_data[256];
+} __attribute__ ((packed));
+
+#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24))
+#define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24))
+
+struct vesa_mode_info {
+ uint16_t mode_attr;
+ uint8_t win_attr[2];
+ uint16_t win_grain;
+ uint16_t win_size;
+ uint16_t win_seg[2];
+ far_ptr_t win_scheme;
+ uint16_t logical_scan;
+
+ uint16_t h_res;
+ uint16_t v_res;
+ uint8_t char_width;
+ uint8_t char_height;
+ uint8_t memory_planes;
+ uint8_t bpp;
+ uint8_t banks;
+ uint8_t memory_layout;
+ uint8_t bank_size;
+ uint8_t image_pages;
+ uint8_t page_function;
+
+ uint8_t rmask;
+ uint8_t rpos;
+ uint8_t gmask;
+ uint8_t gpos;
+ uint8_t bmask;
+ uint8_t bpos;
+ uint8_t resv_mask;
+ uint8_t resv_pos;
+ uint8_t dcm_info;
+
+ uint8_t *lfb_ptr; /* Linear frame buffer address */
+ uint8_t *offscreen_ptr; /* Offscreen memory address */
+ uint16_t offscreen_size;
+
+ uint8_t reserved[206];
+} __attribute__ ((packed));
+
+struct vesa_info {
+ struct vesa_general_info gi;
+ struct vesa_mode_info mi;
+};
+
+extern struct vesa_info vesa_info;
+
+#endif /* LIB_SYS_VESA_H */
diff --git a/com32/menu/menu.h b/com32/menu/menu.h
index 1d7dee80..3be3ba01 100644
--- a/com32/menu/menu.h
+++ b/com32/menu/menu.h
@@ -28,6 +28,9 @@
#include <stdbool.h>
#include "refstr.h"
+/* #define DEBUG 1 */
+#include <dprintf.h>
+
#ifndef CLK_TCK
# define CLK_TCK sysconf(_SC_CLK_TCK)
#endif
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index 1aad5958..135769e1 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -959,7 +959,11 @@ static int parse_one_config(const char *filename)
if (!strcmp(filename, "~"))
filename = syslinux_config_file();
+ dprintf("Opening config file: %s ", filename);
+
f = fopen(filename, "r");
+ dprintf("%s\n", f ? "ok" : "failed");
+
if (!f)
return -1;
diff --git a/doc/memdisk.txt b/doc/memdisk.txt
index 58ec748b..8a308f10 100644
--- a/doc/memdisk.txt
+++ b/doc/memdisk.txt
@@ -75,6 +75,7 @@ b) If the disk image is less than 4,194,304 bytes (4096K, 4 MB) it is
s=# Specify number of sectors (max 63)
floppy[=#] The image is a floppy image[**]
harddisk[=#] The image is a hard disk image[**]
+ iso The image is an El Torito ISO9660 image (drive 0xE0)
# represents a decimal number.
diff --git a/dos/Makefile b/dos/Makefile
index fa2ed0ac..9d8ce33c 100644
--- a/dos/Makefile
+++ b/dos/Makefile
@@ -17,6 +17,7 @@
topdir = ..
include $(topdir)/MCONFIG.embedded
+# CFLAGS += -DDEBUG
LDFLAGS = -T com16.ld
OPTFLAGS = -g
INCLUDES = -include code16.h -nostdinc -iwithprefix include \
@@ -29,7 +30,8 @@ SRCS = syslinux.c \
../libinstaller/mbr_bin.c \
$(wildcard ../libfat/*.c)
OBJS = crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS)))
-LIBOBJS = conio.o memcpy.o memset.o skipatou.o atou.o malloc.o free.o \
+LIBOBJS = int2526.o conio.o memcpy.o memset.o skipatou.o atou.o \
+ malloc.o free.o \
argv.o printf.o __divdi3.o __udivmoddi4.o
VPATH = .:../libfat:../libinstaller
@@ -48,8 +50,8 @@ spotless: clean
installer:
-syslinux.elf: $(OBJS) libcom.a
- $(LD) $(LDFLAGS) -o $@ $^
+syslinux.elf: $(OBJS) libcom.a com16.ld
+ $(LD) $(LDFLAGS) -o $@ $(filter-out %.ld,$^)
libcom.a: $(LIBOBJS)
-rm -f $@
diff --git a/dos/com16.ld b/dos/com16.ld
index 08a1e95e..5f82b73a 100644
--- a/dos/com16.ld
+++ b/dos/com16.ld
@@ -123,5 +123,8 @@ SECTIONS
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
- /DISCARD/ : { *(.note.GNU-stack) }
+ /DISCARD/ : {
+ *(.note.GNU-stack)
+ *(.eh_frame)
+ }
}
diff --git a/dos/int2526.S b/dos/int2526.S
new file mode 100644
index 00000000..bcb7707e
--- /dev/null
+++ b/dos/int2526.S
@@ -0,0 +1,76 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * int 0x25 and 0x26 direct sector access
+ *
+ * Use assembly wrapper functions for these system calls, since unlike
+ * int 0x21 calls they are "dirty" and can destroy unrelated registers.
+ *
+ * NOTE: these all assume the data buffer is in the data segment, i.e.
+ * %ds == %es == dio.bufseg.
+ *
+ * Usage: int int25_read_sector(drive, dio)
+ * Usage: int int26_write_sector(drive, dio)
+ */
+
+ .code16gcc
+ .text
+
+ .globl int25_read_sector
+ .type int25_read_sector, @function
+int25_read_sector:
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ decw %ax /* AL = drive number (0 = A:) */
+ movw %dx, %bx /* BX = dio structure */
+ movw 6(%bx), %dx /* DX = data buffer */
+ movw $-1, %cx
+ int $0x25
+ jc 1f
+ xorw %ax, %ax /* Error code: 0 = no error */
+1:
+ popfw
+ movzwl %ax, %eax
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+ retl
+
+ .globl int26_write_sector
+ .type int26_write_sector, @function
+int26_write_sector:
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ decw %ax /* AL = drive number (0 = A:) */
+ movw %dx, %bx /* BX = dio structure */
+ movw 6(%bx), %dx /* DX = data buffer */
+ movw $-1, %cx
+ int $0x26
+ jc 1f
+ xorw %ax, %ax /* Error code: 0 = no error */
+1:
+ popfw
+ movzwl %ax, %eax
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+ retl
diff --git a/dos/mystuff.h b/dos/mystuff.h
index fbf4e75b..25344413 100644
--- a/dos/mystuff.h
+++ b/dos/mystuff.h
@@ -1,6 +1,8 @@
#ifndef MYSTUFF_H
#define MYSTUFF_H
+#include <inttypes.h>
+
#define NULL ((void *)0)
unsigned int skip_atou(const char **s);
@@ -11,4 +13,12 @@ static inline int isdigit(int ch)
return (ch >= '0') && (ch <= '9');
}
+struct diskio {
+ uint32_t startsector;
+ uint16_t sectors;
+ uint16_t bufoffs, bufseg;
+} __attribute__ ((packed));
+int int25_read_sector(unsigned char drive, struct diskio *dio);
+int int26_write_sector(unsigned char drive, struct diskio *dio);
+
#endif /* MYSTUFF_H */
diff --git a/dos/syslinux.c b/dos/syslinux.c
index 02ae84b9..650c48f6 100644
--- a/dos/syslinux.c
+++ b/dos/syslinux.c
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +21,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <stdarg.h>
#include "mystuff.h"
#include "syslinux.h"
@@ -30,8 +32,15 @@ uint16_t dos_version;
#ifdef DEBUG
# define dprintf printf
+void pause(void)
+{
+ uint16_t ax;
+
+ asm volatile("int $0x16" : "=a" (ax) : "a" (0));
+}
#else
# define dprintf(...) ((void)0)
+# define pause() ((void)0)
#endif
void __attribute__ ((noreturn)) usage(void)
@@ -69,8 +78,9 @@ int creat(const char *filename, int mode)
dprintf("creat(\"%s\", 0x%x)\n", filename, mode);
rv = 0x3C00;
- asm volatile ("int $0x21 ; setc %0":"=bcdm" (err), "+a"(rv)
- :"c"(mode), "d"(filename));
+ asm volatile ("int $0x21 ; setc %0"
+ : "=bcdm" (err), "+a" (rv)
+ : "c" (mode), "d" (filename));
if (err) {
dprintf("rv = %d\n", rv);
die("cannot open ldlinux.sys");
@@ -138,19 +148,13 @@ uint16_t data_segment(void)
{
uint16_t ds;
-asm("movw %%ds,%0":"=rm"(ds));
+ asm("movw %%ds,%0" : "=rm"(ds));
return ds;
}
-struct diskio {
- uint32_t startsector;
- uint16_t sectors;
- uint16_t bufoffs, bufseg;
-} __attribute__ ((packed));
-
void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector)
{
- uint8_t err;
+ uint16_t errnum;
struct diskio dio;
dprintf("write_device(%d,%p,%u,%u)\n", drive, buf, nsecs, sector);
@@ -160,16 +164,27 @@ void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector)
dio.bufoffs = (uintptr_t) buf;
dio.bufseg = data_segment();
- asm volatile ("int $0x26 ; setc %0 ; popfw":"=abcdm" (err)
- :"a"(drive - 1), "b"(&dio), "c"(-1), "d"(buf), "m"(dio));
+ /* Try FAT32-aware system call first */
+ asm volatile("int $0x21 ; jc 1f ; xorw %0,%0\n"
+ "1:"
+ : "=a" (errnum)
+ : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive),
+ "S" (1), "m" (dio)
+ : "memory");
- if (err)
+ /* If not supported, try the legacy system call (int2526.S) */
+ if (errnum == 0x0001)
+ errnum = int26_write_sector(drive, &dio);
+
+ if (errnum) {
+ dprintf("rv = %04x\n", errnum);
die("sector write error");
+ }
}
void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector)
{
- uint8_t err;
+ uint16_t errnum;
struct diskio dio;
dprintf("read_device(%d,%p,%u,%u)\n", drive, buf, nsecs, sector);
@@ -179,11 +194,21 @@ void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector)
dio.bufoffs = (uintptr_t) buf;
dio.bufseg = data_segment();
- asm volatile ("int $0x25 ; setc %0 ; popfw":"=abcdm" (err)
- :"a"(drive - 1), "b"(&dio), "c"(-1), "d"(buf), "m"(dio));
+ /* Try FAT32-aware system call first */
+ asm volatile("int $0x21 ; jc 1f ; xorw %0,%0\n"
+ "1:"
+ : "=a" (errnum)
+ : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive),
+ "S" (0), "m" (dio));
- if (err)
+ /* If not supported, try the legacy system call (int2526.S) */
+ if (errnum == 0x0001)
+ errnum = int25_read_sector(drive, &dio);
+
+ if (errnum) {
+ dprintf("rv = %04x\n", errnum);
die("sector read error");
+ }
}
/* Both traditional DOS and FAT32 DOS return this structure, but
@@ -218,15 +243,17 @@ uint32_t get_partition_offset(int drive)
dp.specfunc = 1; /* Get current information */
rv = 0x440d;
- asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv), "=m"(dp)
- :"b"(drive), "c"(0x0860), "d"(&dp));
+ asm volatile ("int $0x21 ; setc %0"
+ :"=abcdm" (err), "+a"(rv), "=m"(dp)
+ :"b" (drive), "c" (0x0860), "d" (&dp));
if (!err)
return dp.hiddensecs;
rv = 0x440d;
- asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv), "=m"(dp)
- :"b"(drive), "c"(0x4860), "d"(&dp));
+ asm volatile ("int $0x21 ; setc %0"
+ : "=abcdm" (err), "+a" (rv), "=m" (dp)
+ : "b" (drive), "c" (0x4860), "d" (&dp));
if (!err)
return dp.hiddensecs;
@@ -259,22 +286,26 @@ void write_mbr(int drive, const void *buf)
uint16_t rv;
uint8_t err;
- dprintf("write_mbr(%d,%p)\n", drive, buf);
+ dprintf("write_mbr(%d,%p)", drive, buf);
mbr.bufferoffset = (uintptr_t) buf;
mbr.bufferseg = data_segment();
rv = 0x440d;
- asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv)
+ asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv)
:"c"(0x0841), "d"(&mbr), "b"(drive), "m"(mbr));
- if (!err)
+ dprintf(" rv(0841) = %04x", rv);
+ if (!err) {
+ dprintf("\n");
return;
+ }
rv = 0x440d;
- asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv)
+ asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv)
:"c"(0x4841), "d"(&mbr), "b"(drive), "m"(mbr));
+ dprintf(" rv(4841) = %04x\n", rv);
if (err)
die("mbr write error");
}
@@ -284,7 +315,7 @@ void read_mbr(int drive, const void *buf)
uint16_t rv;
uint8_t err;
- dprintf("read_mbr(%d,%p)\n", drive, buf);
+ dprintf("read_mbr(%d,%p)", drive, buf);
mbr.bufferoffset = (uintptr_t) buf;
mbr.bufferseg = data_segment();
@@ -293,15 +324,29 @@ void read_mbr(int drive, const void *buf)
asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv)
:"c"(0x0861), "d"(&mbr), "b"(drive), "m"(mbr));
- if (!err)
+ dprintf(" rv(0861) = %04x", rv);
+ if (!err) {
+ dprintf("\n");
return;
+ }
rv = 0x440d;
asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv)
:"c"(0x4861), "d"(&mbr), "b"(drive), "m"(mbr));
+ dprintf(" rv(4841) = %04x\n", rv);
if (err)
die("mbr read error");
+
+ dprintf("Bytes: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ ((const uint8_t *)buf)[0],
+ ((const uint8_t *)buf)[1],
+ ((const uint8_t *)buf)[2],
+ ((const uint8_t *)buf)[3],
+ ((const uint8_t *)buf)[4],
+ ((const uint8_t *)buf)[5],
+ ((const uint8_t *)buf)[6],
+ ((const uint8_t *)buf)[7]);
}
/* This call can legitimately fail, and we don't care, so ignore error return */
@@ -327,54 +372,95 @@ int libfat_xpread(intptr_t pp, void *buf, size_t secsize,
static inline void get_dos_version(void)
{
- uint16_t ver = 0x3001;
-asm("int $0x21 ; xchgb %%ah,%%al": "+a"(ver): :"ebx", "ecx");
+ uint16_t ver;
+
+ asm("int $0x21 ; xchgb %%ah,%%al"
+ : "=a" (ver)
+ : "a" (0x3001)
+ : "ebx", "ecx");
dos_version = ver;
+
dprintf("DOS version %d.%d\n", (dos_version >> 8), dos_version & 0xff);
}
/* The locking interface relies on static variables. A massive hack :( */
-static uint16_t lock_level;
+static uint8_t lock_level, lock_drive;
static inline void set_lock_device(uint8_t device)
{
- lock_level = device;
+ lock_level = 0;
+ lock_drive = device;
}
-void lock_device(int level)
+static int do_lock(uint8_t level)
{
+ uint16_t level_arg = lock_drive + (level << 8);
uint16_t rv;
uint8_t err;
- uint16_t lock_call;
-
- if (dos_version < 0x0700)
- return; /* Win9x/NT only */
-
#if 0
/* DOS 7.10 = Win95 OSR2 = first version with FAT32 */
- lock_call = (dos_version >= 0x0710) ? 0x484A : 0x084A;
+ uint16_t lock_call = (dos_version >= 0x070a) ? 0x484A : 0x084A;
#else
- lock_call = 0x084A; /* MSDN says this is OK for all filesystems */
+ uint16_t lock_call = 0x084A; /* MSDN says this is OK for all filesystems */
#endif
- while ((lock_level >> 8) < level) {
- uint16_t new_level = lock_level + 0x0100;
- dprintf("Trying lock %04x...\n", new_level);
- rv = 0x444d;
- asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv)
- :"b"(new_level), "c"(lock_call), "d"(0x0001));
+ dprintf("Trying lock %04x... ", level_arg);
+ asm volatile ("int $0x21 ; setc %0"
+ : "=bcdm" (err), "=a" (rv)
+ : "a" (0x440d), "b" (level_arg),
+ "c" (lock_call), "d" (0x0001));
+ dprintf("%s %04x\n", err ? "err" : "ok", rv);
+
+ return err ? rv : 0;
+}
+
+void lock_device(int level)
+{
+ static int hard_lock = 0;
+ int err;
+
+ if (dos_version < 0x0700)
+ return; /* Win9x/NT only */
+
+ if (!hard_lock) {
+ /* Assume hierarchial "soft" locking supported */
+
+ while (lock_level < level) {
+ int new_level = lock_level + 1;
+ err = do_lock(new_level);
+ if (err) {
+ if (err == 0x0001) {
+ /* Try hard locking next */
+ hard_lock = 1;
+ }
+ goto soft_fail;
+ }
+
+ lock_level = new_level;
+ }
+ return;
+ }
+
+soft_fail:
+ if (hard_lock) {
+ /* Hard locking, only level 4 supported */
+ /* This is needed for Win9x in DOS mode */
+
+ err = do_lock(4);
if (err) {
- /* rv == 0x0001 means this call is not supported, if so we
- assume locking isn't needed (e.g. Win9x in DOS-only mode) */
- if (rv == 0x0001)
+ if (err == 0x0001) {
+ /* Assume locking is not needed */
return;
- else
- die("could not lock device");
+ }
+ goto hard_fail;
}
- lock_level = new_level;
+ lock_level = 4;
+ return;
}
- return;
+
+hard_fail:
+ die("could not lock device");
}
void unlock_device(int level)
@@ -388,16 +474,23 @@ void unlock_device(int level)
#if 0
/* DOS 7.10 = Win95 OSR2 = first version with FAT32 */
- unlock_call = (dos_version >= 0x0710) ? 0x486A : 0x086A;
+ unlock_call = (dos_version >= 0x070a) ? 0x486A : 0x086A;
#else
unlock_call = 0x086A; /* MSDN says this is OK for all filesystems */
#endif
- while ((lock_level >> 8) > level) {
- uint16_t new_level = lock_level - 0x0100;
+ if (lock_level == 4 && level > 0)
+ return; /* Only drop the hard lock at the end */
+
+ while (lock_level > level) {
+ uint8_t new_level = (lock_level == 4) ? 0 : lock_level - 1;
+ uint16_t level_arg = (new_level << 8) + lock_drive;
rv = 0x440d;
- asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv)
- :"b"(new_level), "c"(unlock_call));
+ dprintf("Trying unlock %04x... ", new_level);
+ asm volatile ("int $0x21 ; setc %0"
+ : "=bcdm" (err), "+a" (rv)
+ : "b" (level_arg), "c" (unlock_call));
+ dprintf("%s %04x\n", err ? "err" : "ok", rv);
lock_level = new_level;
}
}
@@ -438,6 +531,8 @@ static void adjust_mbr(int device, int writembr, int set_active)
struct mbr_entry *me = (struct mbr_entry *)(sectbuf + 446);
int found = 0;
+ dprintf("Searching for partition offset: %08x\n", offset);
+
for (i = 0; i < 4; i++) {
if (me->startlba == offset) {
me->active = 0x80;
@@ -449,7 +544,7 @@ static void adjust_mbr(int device, int writembr, int set_active)
}
if (found < 1) {
- die("partition not found");
+ die("partition not found (-a is not implemented for logical partitions)");
} else if (found > 1) {
die("multiple aliased partitions found");
}
@@ -556,10 +651,11 @@ int main(int argc, char *argv[])
ldlinux_name[0] = dev_fd | 0x40;
- set_attributes(ldlinux_name, 0);
- fd = creat(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */
+ set_attributes(ldlinux_name, 0x00);
+ fd = creat(ldlinux_name, 0);
write_file(fd, syslinux_ldlinux, syslinux_ldlinux_len);
close(fd);
+ set_attributes(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */
/*
* Now, use libfat to create a block map. This probably
@@ -631,7 +727,7 @@ int main(int argc, char *argv[])
/*
* Write the now-patched first sector of ldlinux.sys
*/
- lock_device(3);
+ /* lock_device(3); -- doesn't seem to be needed */
write_device(dev_fd, syslinux_ldlinux, 1, sectors[0]);
/*
diff --git a/memdisk/Makefile b/memdisk/Makefile
index d185d87c..09f17c8e 100644
--- a/memdisk/Makefile
+++ b/memdisk/Makefile
@@ -38,11 +38,15 @@ endif
# Important: init.o16 must be first!!
OBJS16 = init.o16 init32.o
OBJS32 = start32.o setup.o msetup.o e820func.o conio.o memcpy.o memset.o \
- memmove.o unzip.o memdisk_chs.o memdisk_edd.o
+ memmove.o unzip.o dskprobe.o eltorito.o \
+ memdisk_chs_512.o memdisk_edd_512.o \
+ memdisk_iso_512.o memdisk_iso_2048.o
-CSRC = setup.c msetup.c e820func.c conio.c unzip.c
+CSRC = setup.c msetup.c e820func.c conio.c unzip.c dskprobe.c eltorito.c
SSRC = start32.S memcpy.S memset.S memmove.S
-NASMSRC = memdisk_chs.asm memdisk_edd.asm memdisk16.asm
+NASMSRC = memdisk_chs_512.asm memdisk_edd_512.asm \
+ memdisk_iso_512.asm memdisk_iso_2048.asm \
+ memdisk16.asm
all: memdisk # e820test
diff --git a/memdisk/bda.h b/memdisk/bda.h
new file mode 100644
index 00000000..cfac441f
--- /dev/null
+++ b/memdisk/bda.h
@@ -0,0 +1,56 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdint.h>
+
+/* Addresses in the zero page */
+#define BIOS_INT13 (0x13*4) /* INT 13h vector */
+#define BIOS_INT15 (0x15*4) /* INT 15h vector */
+#define BIOS_INT1E (0x1E*4) /* INT 1Eh vector */
+#define BIOS_INT40 (0x40*4) /* INT 13h vector */
+#define BIOS_INT41 (0x41*4) /* INT 41h vector */
+#define BIOS_INT46 (0x46*4) /* INT 46h vector */
+#define BIOS_BASEMEM 0x413 /* Amount of DOS memory */
+#define BIOS_EQUIP 0x410 /* BIOS equipment list */
+#define BIOS_HD_COUNT 0x475 /* Number of hard drives present */
+
+/* Access to objects in the zero page */
+static inline void wrz_8(uint32_t addr, uint8_t data)
+{
+ *((uint8_t *) addr) = data;
+}
+
+static inline void wrz_16(uint32_t addr, uint16_t data)
+{
+ *((uint16_t *) addr) = data;
+}
+
+static inline void wrz_32(uint32_t addr, uint32_t data)
+{
+ *((uint32_t *) addr) = data;
+}
+
+static inline uint8_t rdz_8(uint32_t addr)
+{
+ return *((uint8_t *) addr);
+}
+
+static inline uint16_t rdz_16(uint32_t addr)
+{
+ return *((uint16_t *) addr);
+}
+
+static inline uint32_t rdz_32(uint32_t addr)
+{
+ return *((uint32_t *) addr);
+}
diff --git a/memdisk/dskprobe.c b/memdisk/dskprobe.c
new file mode 100644
index 00000000..de858bb9
--- /dev/null
+++ b/memdisk/dskprobe.c
@@ -0,0 +1,114 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Shao Miller - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dskprobe.c
+ *
+ * Routines for probing BIOS disk drives
+ */
+
+/*
+ * Uncomment for debugging
+ *
+ * #define DBG_DSKPROBE 1
+ */
+
+#include <stdint.h>
+#include "memdisk.h"
+#include "bda.h"
+#include "conio.h"
+
+/*
+ * We will probe a BIOS drive numer using INT 13h, AH=probe
+ * and will pass along that call's success or failure
+ */
+int probe_int13_ah(uint8_t drive, uint8_t probe)
+{
+ int err;
+ com32sys_t regs;
+
+ memset(&regs, 0, sizeof regs);
+
+ regs.eax.b[1] = probe; /* AH = probe */
+ regs.edx.b[0] = drive; /* DL = drive number to probe */
+ intcall(0x13, &regs, &regs);
+
+ err = !(regs.eflags.l & 1);
+#ifdef DBG_DSKPROBE
+ printf("probe_int13_ah(0x%02x, 0x%02x) == %d\n", drive, probe, err);
+#endif
+ return err;
+}
+
+/*
+ * We will probe the BIOS Data Area and count the drives found there.
+ * This heuristic then assumes that all drives of 'drive's type are
+ * found in a contiguous range, and returns 1 if the probed drive
+ * is less than or equal to the BDA count.
+ * This particular function's code is derived from code in setup.c by
+ * H. Peter Anvin. Please respect that file's copyright for this function
+ */
+int probe_bda_drive(uint8_t drive)
+{
+ int bios_drives;
+ int err;
+
+ if (drive & 0x80) {
+ bios_drives = rdz_8(BIOS_HD_COUNT); /* HDD count */
+ } else {
+ uint8_t equip = rdz_8(BIOS_EQUIP);
+ if (equip & 1)
+ bios_drives = (equip >> 6) + 1; /* Floppy count */
+ else
+ bios_drives = 0;
+ }
+ err = (drive - (drive & 0x80)) >= bios_drives ? 0 : 1;
+#ifdef DBG_DSKPROBE
+ printf("probe_bda_drive(0x%02x) == %d, count: %d\n",
+ drive, err, bios_drives);
+#endif
+ return err;
+}
+
+/*
+ * We will probe a drive with a few different methods, returning
+ * the count of succesful probes
+ */
+int probe_drive(uint8_t drive)
+{
+ int c = 0;
+ /* Only probe the BDA for floppies */
+ if (drive & 0x80) {
+ c += probe_int13_ah(drive, 0x08);
+ c += probe_int13_ah(drive, 0x15);
+ c += probe_int13_ah(drive, 0x41);
+ }
+ c += probe_bda_drive(drive);
+ return c;
+}
+
+/*
+ * We will probe a contiguous range of BIOS drive, starting with drive
+ * number 'start'. We probe with a few different methods, and return
+ * the first drive which doesn't respond to any of the probes.
+ */
+uint8_t probe_drive_range(uint8_t start)
+{
+ uint8_t drive = start;
+ while (probe_drive(drive)) {
+ drive++;
+ /* Check for passing the floppy/HDD boundary */
+ if ((drive & 0x7F) == 0)
+ break;
+ }
+ return drive;
+}
diff --git a/memdisk/dskprobe.h b/memdisk/dskprobe.h
new file mode 100644
index 00000000..99bfa666
--- /dev/null
+++ b/memdisk/dskprobe.h
@@ -0,0 +1,21 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Shao Miller - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dskprobe.h
+ *
+ * Routines for probing BIOS disk drives
+ */
+
+#include <stdint.h>
+
+extern uint8_t probe_drive_range(uint8_t);
diff --git a/memdisk/eltorito.c b/memdisk/eltorito.c
new file mode 100644
index 00000000..7e0ba89b
--- /dev/null
+++ b/memdisk/eltorito.c
@@ -0,0 +1,58 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Shao Miller - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * eltorito.c
+ *
+ * EDD-4 El Torito structures and debugging routines
+ */
+
+#include <stdint.h>
+#include "memdisk.h"
+#include "conio.h"
+#include "eltorito.h"
+
+#ifdef DBG_ELTORITO
+void eltorito_dump(uint32_t image)
+{
+ printf("-- El Torito dump --\n", image);
+
+ /* BVD starts at sector 17. */
+ struct edd4_bvd *bvd = (struct edd4_bvd *)(image + 17 * 2048);
+
+ printf("bvd.boot_rec_ind: 0x%02x\n", bvd->boot_rec_ind);
+ printf("bvd.iso9660_id: %c%c%c%c%c\n", bvd->iso9660_id[0],
+ bvd->iso9660_id[1], bvd->iso9660_id[2], bvd->iso9660_id[3],
+ bvd->iso9660_id[4]);
+ printf("bvd.ver: 0x%02x\n", bvd->ver);
+ printf("bvd.eltorito: %s\n", bvd->eltorito);
+ printf("bvd.boot_cat: 0x%08x\n", bvd->boot_cat);
+
+ struct edd4_bootcat *boot_cat =
+ (struct edd4_bootcat *)(image + bvd->boot_cat * 2048);
+
+ printf("boot_cat.validation_entry\n");
+ printf(" .header_id: 0x%02x\n", boot_cat->validation_entry.header_id);
+ printf(" .platform_id: 0x%02x\n", boot_cat->validation_entry.platform_id);
+ printf(" .id_string: %s\n", boot_cat->validation_entry.id_string);
+ printf(" .checksum: 0x%04x\n", boot_cat->validation_entry.checksum);
+ printf(" .key55: 0x%02x\n", boot_cat->validation_entry.key55);
+ printf(" .keyAA: 0x%02x\n", boot_cat->validation_entry.keyAA);
+ printf("boot_cat.initial_entry\n");
+ printf(" .header_id: 0x%02x\n", boot_cat->initial_entry.header_id);
+ printf(" .media_type: 0x%02x\n", boot_cat->initial_entry.media_type);
+ printf(" .load_seg: 0x%04x\n", boot_cat->initial_entry.load_seg);
+ printf(" .system_type: 0x%02x\n", boot_cat->initial_entry.system_type);
+ printf(" .sect_count: %d\n", boot_cat->initial_entry.sect_count);
+ printf(" .load_block: 0x%08x\n", boot_cat->initial_entry.load_block);
+}
+#endif
diff --git a/memdisk/eltorito.h b/memdisk/eltorito.h
new file mode 100644
index 00000000..7d46e1d9
--- /dev/null
+++ b/memdisk/eltorito.h
@@ -0,0 +1,83 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Shao Miller - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * eltorito.h
+ *
+ * EDD-4 El Torito structures and debugging routines
+ */
+
+#include <stdint.h>
+
+/*
+ * Uncomment for El Torito debugging
+ *
+ * #define DBG_ELTORITO 1
+ */
+
+#ifdef DBG_ELTORITO
+extern void eltorito_dump(uint32_t);
+#endif
+
+/* EDD-4 Bootable Optical Disc Drive Boot Volume Descriptor */
+struct edd4_bvd {
+ uint8_t boot_rec_ind; /* Boot Record Indicator */
+ uint8_t iso9660_id[5]; /* ISO9660 ID */
+ uint8_t ver; /* Descriptor Version */
+ uint8_t eltorito[32]; /* "EL TORITO" etc. */
+ uint8_t res1[32]; /* Reserved */
+ uint32_t boot_cat; /* Boot catalog sector */
+ uint8_t res2[1973]; /* Reserved */
+} __attribute__ ((packed));
+
+struct validation_entry {
+ uint8_t header_id; /* Header ID */
+ uint8_t platform_id; /* Platform ID */
+ uint16_t res1; /* Reserved */
+ uint8_t id_string[24]; /* Manufacturer */
+ uint16_t checksum; /* Sums with whole record to zero */
+ uint8_t key55; /* Key byte 0x55 */
+ uint8_t keyAA; /* Key byte 0xAA */
+} __attribute__ ((packed));
+
+struct initial_entry {
+ uint8_t header_id; /* Header ID */
+ uint8_t media_type; /* Media type */
+ uint16_t load_seg; /* Load segment */
+ uint8_t system_type; /* (Filesystem ID) */
+ uint8_t res1; /* Reserved */
+ uint16_t sect_count; /* Emulated sectors to load */
+ uint32_t load_block; /* Starting sector of image */
+ uint8_t res2[4]; /* Reserved */
+} __attribute__ ((packed));
+
+/* EDD-4 Bootable Optical Disc Drive Boot Catalog (fixed-size portions) */
+struct edd4_bootcat {
+ struct validation_entry validation_entry;
+ struct initial_entry initial_entry;
+} __attribute__ ((packed));
+
+/* EDD-4 CD Specification Packet */
+struct edd4_cd_pkt {
+ uint8_t size; /* Packet size */
+ uint8_t type; /* Boot media type (flags) */
+ uint8_t driveno; /* INT 13h drive number */
+ uint8_t controller; /* Controller index */
+ uint32_t start; /* Starting LBA of image */
+ uint16_t devno; /* Device number */
+ uint16_t userbuf; /* User buffer segment */
+ uint16_t load_seg; /* Load segment */
+ uint16_t sect_count; /* Emulated sectors to load */
+ uint8_t geom1; /* Cylinders bits 0 thru 7 */
+ uint8_t geom2; /* Sects/track 0 thru 5, cyls 8, 9 */
+ uint8_t geom3; /* Heads */
+} __attribute__ ((packed));
diff --git a/memdisk/memdisk.inc b/memdisk/memdisk.inc
index 3c79b624..a37218b5 100644
--- a/memdisk/memdisk.inc
+++ b/memdisk/memdisk.inc
@@ -8,6 +8,7 @@
;
; Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+; Portions copyright 2009 Shao Miller [El Torito code]
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
@@ -79,7 +80,6 @@
org 0h
-%define SECTORSIZE_LG2 9 ; log2(sector size)
%define SECTORSIZE (1 << SECTORSIZE_LG2)
; Parameter registers definition; this is the definition
@@ -136,6 +136,10 @@ Int13Start:
mov ss,ax
mov sp,[cs:MyStack]
+%if ELTORITO
+ cmp word [cs:SavedAX],4a00h ; El Torito function?
+ jae our_drive ; We grab it
+%endif
; See if DL points to our class of device (FD, HD)
push dx
push dx
@@ -147,6 +151,12 @@ Int13Start:
jz our_drive ; If ZF=1, we have an exact match
cmp dl,[cs:DriveNo]
jb .nomatch ; Drive < Our drive
+ cmp dl,[cs:DriveShiftLimit]
+ jae .nomatch ; Drive > The maximum drive
+ ; number that we will shift for.
+ ; This leaves any higher-up BIOS
+ ; drives alone, such as an optical
+ ; disc drive 0xA0 or 0xE0
dec dl ; Drive > Our drive, adjust drive #
.nomatch:
TRACER '!'
@@ -164,7 +174,9 @@ Int13Start:
cmp byte [cs:SavedAX+1],08h ; Get drive params function?
je .norestoredl ; DL = number of drives
cmp byte [cs:SavedAX+1],15h ; Get disk type function?
- je .norestoredl ; CX:DX = size of device
+ jne .restoredl
+ test byte [bp+4],80h ; Hard disk?
+ jnz .norestoredl ; CX:DX = size of device
.restoredl:
mov dl,[bp+4]
.norestoredl:
@@ -200,6 +212,14 @@ our_drive:
; Note: AX == P_AX here
cmp ah,Int13FuncsCnt-1
ja Invalid_jump
+%if ELTORITO
+ mov al,[CD_PKT.type] ; Check if we are in
+ cmp al,0 ; El Torito no emulation mode
+ ja .emulation ; No. We support the function
+ cmp ah,3fh ; Yes. We must not support functions
+ jbe Invalid_jump ; 0 through 3Fh. Check and decide
+.emulation:
+%endif
xor al,al ; AL = 0 is standard entry condition
mov di,ax
shr di,7 ; Convert AH to an offset in DI
@@ -388,8 +408,9 @@ EDDPresence:
jne Invalid
mov P_BX,0AA55h ; EDD signature
mov P_AX,03000h ; EDD 3.0
- mov P_CX,0003h ; Bit 0 - Fixed disk access subset
+ mov P_CX,0007h ; Bit 0 - Fixed disk access subset
; Bit 1 - Locking and ejecting subset
+ ; Bit 2 - EDD subset
pop ax ; Drop return address
xor ax,ax ; Success
jmp DoneWeird ; Success, but AH != 0, sigh...
@@ -570,10 +591,31 @@ edd_setup_regs:
EDDEject:
mov ax,0B200h ; Volume Not Removable
ret
-
+%if ELTORITO
+ElToritoTerminate:
+ TRACER 'T'
+ mov ax,[cs:SavedAX]
+ cmp al,1 ; We only support query, not terminate
+ jne ElToritoErr ; Fail
+ mov es,P_DS ; Caller's DS:SI pointed to packet
+ mov di,P_SI ; We'll use ES:DI
+ mov si,CD_PKT.size ; First byte is packet size
+ xor cx,0 ; Empty our count
+ ;mov cl,[ds:si] ; We'll copy that many bytes
+ mov cl,13h
+ rep movsb ; Copy until CX is zero
+ mov ax,0 ; Success
+ ret
+ElToritoEmulate:
+ElToritoBoot:
+ElToritoCatalog:
+ElToritoErr:
+ TRACER '!'
+ mov ax,100h ; Invalid parameter
+ ret
+%endif ; ELTORITO
%endif ; EDD
-
;
; INT 15h intercept routines
;
@@ -955,7 +997,14 @@ Int13Funcs dw Reset ; 00h - RESET
dw EDDSeek ; 47h - EDD SEEK
dw EDDGetParms ; 48h - EDD GET PARAMETERS
dw EDDDetectChange ; 49h - EDD MEDIA CHANGE STATUS
-%endif
+%if ELTORITO ; EDD El Torito Functions
+ ; ELTORITO _must_ also have EDD
+ dw ElToritoEmulate ; 4Ah - Initiate Disk Emulation
+ dw ElToritoTerminate ; 4Bh - Terminate Disk Emulation
+ dw ElToritoBoot ; 4Ch - Initiate Disk Emu. and Reboot
+ dw ElToritoCatalog ; 4Dh - Return Boot Catalog
+%endif ; ELTORITO
+%endif ; EDD
Int13FuncsEnd equ $
Int13FuncsCnt equ (Int13FuncsEnd-Int13Funcs) >> 1
@@ -1013,6 +1062,13 @@ DPT_ptr dw 0 ; If nonzero, pointer to DPT
MDI_Len equ $-MemDisk_Info
; ---- MDI structure ends here ---
+DriveShiftLimit db 0ffh ; Installer will [soon] probe for
+ ; a range of contiguous drives.
+ ; Any BIOS drives above this region
+ ; shall not be impacted by our
+ ; shifting behaviour
+ db 0 ; pad to a DWORD
+ dw 0 ; pad to a QWORD
MemInt1588 dw 0 ; 1MB-65MB memory amount (1K)
Cylinders dw 0 ; Cylinder count
@@ -1058,7 +1114,24 @@ EDD_DPT:
.res3 db 0 ; Reserved
.chksum db 0 ; DPI checksum
-%endif
+%if ELTORITO
+; El Torito CD Specification Packet - mostly filled in by installer
+CD_PKT:
+.size db 13h ; Packet size (19 bytes)
+.type db 0 ; Boot media type (flags)
+.driveno db 0E0h ; INT 13h drive number
+.controller db 0 ; Controller index
+.start dd 0 ; Starting LBA of image
+.devno dw 0 ; Device number
+.user_buf dw 0 ; User buffer segment
+.load_seg dw 0 ; Load segment
+.sect_count dw 0 ; Emulated sectors to load
+.geom1 db 0 ; Cylinders bits 0 thru 7
+.geom2 db 0 ; Sects/track 0 thru 5, cyls 8, 9
+.geom3 db 0 ; Heads
+%endif ; ELTORITO
+
+%endif ; EDD
; End patch area
alignb 4, db 0
diff --git a/memdisk/memdisk_chs.asm b/memdisk/memdisk_chs.asm
deleted file mode 100644
index 94dad9db..00000000
--- a/memdisk/memdisk_chs.asm
+++ /dev/null
@@ -1,3 +0,0 @@
- [map all memdisk_chs.map]
-%define EDD 0
-%include "memdisk.inc"
diff --git a/memdisk/memdisk_chs_512.asm b/memdisk/memdisk_chs_512.asm
new file mode 100644
index 00000000..bb436f35
--- /dev/null
+++ b/memdisk/memdisk_chs_512.asm
@@ -0,0 +1,5 @@
+ [map all memdisk_chs_512.map]
+%define EDD 0
+%define ELTORITO 0
+%define SECTORSIZE_LG2 9 ; log2(sector size)
+%include "memdisk.inc"
diff --git a/memdisk/memdisk_edd.asm b/memdisk/memdisk_edd.asm
deleted file mode 100644
index 6f909d74..00000000
--- a/memdisk/memdisk_edd.asm
+++ /dev/null
@@ -1,3 +0,0 @@
- [map all memdisk_edd.map]
-%define EDD 1
-%include "memdisk.inc"
diff --git a/memdisk/memdisk_edd_512.asm b/memdisk/memdisk_edd_512.asm
new file mode 100644
index 00000000..3a6d5ca1
--- /dev/null
+++ b/memdisk/memdisk_edd_512.asm
@@ -0,0 +1,5 @@
+ [map all memdisk_edd_512.map]
+%define EDD 1
+%define ELTORITO 0
+%define SECTORSIZE_LG2 9 ; log2(sector size)
+%include "memdisk.inc"
diff --git a/memdisk/memdisk_iso_2048.asm b/memdisk/memdisk_iso_2048.asm
new file mode 100644
index 00000000..0c8ffee3
--- /dev/null
+++ b/memdisk/memdisk_iso_2048.asm
@@ -0,0 +1,5 @@
+ [map all memdisk_iso_2048.map]
+%define EDD 1
+%define ELTORITO 1
+%define SECTORSIZE_LG2 11 ; log2(sector size)
+%include "memdisk.inc"
diff --git a/memdisk/memdisk_iso_512.asm b/memdisk/memdisk_iso_512.asm
new file mode 100644
index 00000000..1555b772
--- /dev/null
+++ b/memdisk/memdisk_iso_512.asm
@@ -0,0 +1,5 @@
+ [map all memdisk_iso_512.map]
+%define EDD 1
+%define ELTORITO 1
+%define SECTORSIZE_LG2 9 ; log2(sector size)
+%include "memdisk.inc"
diff --git a/memdisk/setup.c b/memdisk/setup.c
index 52781694..db986faa 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -2,6 +2,7 @@
*
* Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
* Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Portions copyright 2009 Shao Miller [El Torito code]
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -12,7 +13,10 @@
* ----------------------------------------------------------------------- */
#include <stdint.h>
+#include "bda.h"
+#include "dskprobe.h"
#include "e820.h"
+#include "eltorito.h"
#include "conio.h"
#include "version.h"
#include "memdisk.h"
@@ -22,12 +26,18 @@ const char memdisk_version[] = "MEMDISK " VERSION_STR " " DATE;
const char copyright[] =
"Copyright " FIRSTYEAR "-" YEAR_STR " H. Peter Anvin et al";
-extern const char _binary_memdisk_chs_bin_start[];
-extern const char _binary_memdisk_chs_bin_end[];
-extern const char _binary_memdisk_chs_bin_size[];
-extern const char _binary_memdisk_edd_bin_start[];
-extern const char _binary_memdisk_edd_bin_end[];
-extern const char _binary_memdisk_edd_bin_size[];
+extern const char _binary_memdisk_chs_512_bin_start[];
+extern const char _binary_memdisk_chs_512_bin_end[];
+extern const char _binary_memdisk_chs_512_bin_size[];
+extern const char _binary_memdisk_edd_512_bin_start[];
+extern const char _binary_memdisk_edd_512_bin_end[];
+extern const char _binary_memdisk_edd_512_bin_size[];
+extern const char _binary_memdisk_iso_512_bin_start[];
+extern const char _binary_memdisk_iso_512_bin_end[];
+extern const char _binary_memdisk_iso_512_bin_size[];
+extern const char _binary_memdisk_iso_2048_bin_start[];
+extern const char _binary_memdisk_iso_2048_bin_end[];
+extern const char _binary_memdisk_iso_2048_bin_size[];
struct memdisk_header {
uint16_t int13_offs;
@@ -106,6 +116,10 @@ struct patch_area {
uint16_t dpt_ptr;
/* End of the official MemDisk_Info */
+ uint8_t driveshiftlimit; /* Do not shift drives above this region */
+ uint8_t _pad2; /* Pad to DWORD */
+ uint16_t _pad3; /* Pad to QWORD */
+
uint16_t memint1588;
uint16_t cylinders;
@@ -131,51 +145,18 @@ struct patch_area {
dpt_t dpt;
struct edd_dpt edd_dpt;
+ struct edd4_cd_pkt cd_pkt; /* Only really in a memdisk_iso_* hook */
} __attribute__((packed));
-/* Access to high memory */
-
-/* Access to objects in the zero page */
-static inline void wrz_8(uint32_t addr, uint8_t data)
-{
- *((uint8_t *) addr) = data;
-}
-
-static inline void wrz_16(uint32_t addr, uint16_t data)
-{
- *((uint16_t *) addr) = data;
-}
-
-static inline void wrz_32(uint32_t addr, uint32_t data)
-{
- *((uint32_t *) addr) = data;
-}
-
-static inline uint8_t rdz_8(uint32_t addr)
-{
- return *((uint8_t *) addr);
-}
-
-static inline uint16_t rdz_16(uint32_t addr)
-{
- return *((uint16_t *) addr);
-}
-
-static inline uint32_t rdz_32(uint32_t addr)
-{
- return *((uint32_t *) addr);
-}
-
-/* Addresses in the zero page */
-#define BIOS_INT13 (0x13*4) /* INT 13h vector */
-#define BIOS_INT15 (0x15*4) /* INT 15h vector */
-#define BIOS_INT1E (0x1E*4) /* INT 1Eh vector */
-#define BIOS_INT40 (0x40*4) /* INT 13h vector */
-#define BIOS_INT41 (0x41*4) /* INT 41h vector */
-#define BIOS_INT46 (0x46*4) /* INT 46h vector */
-#define BIOS_BASEMEM 0x413 /* Amount of DOS memory */
-#define BIOS_EQUIP 0x410 /* BIOS equipment list */
-#define BIOS_HD_COUNT 0x475 /* Number of hard drives present */
+/* An EDD disk packet */
+struct edd_dsk_pkt {
+ uint8_t size; /* Packet size */
+ uint8_t res1; /* Reserved */
+ uint16_t count; /* Count to transfer */
+ uint32_t buf; /* Buffer pointer */
+ uint64_t start; /* LBA to start from */
+ uint64_t buf64; /* 64-bit buf pointer */
+} __attribute__ ((packed));
/*
* Routine to seek for a command-line item and return a pointer
@@ -339,7 +320,7 @@ void unzip_if_needed(uint32_t * where_p, uint32_t * size_p)
if (!okmem)
die("Not enough memory to decompress image (need 0x%08x bytes)\n",
- gzdatasize);
+ gzdatasize);
printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ",
target, gzdatasize);
@@ -354,11 +335,13 @@ void unzip_if_needed(uint32_t * where_p, uint32_t * size_p)
* Figure out the "geometry" of the disk in question
*/
struct geometry {
- uint32_t sectors; /* 512-byte sector count */
+ uint32_t sectors; /* Sector count */
uint32_t c, h, s; /* C/H/S geometry */
uint32_t offset; /* Byte offset for disk */
+ uint32_t boot_lba; /* LBA of bootstrap code */
uint8_t type; /* Type byte for INT 13h AH=08h */
uint8_t driveno; /* Drive no */
+ uint16_t sector_size; /* Sector size in bytes (512 vs. 2048) */
const char *hsrc, *ssrc; /* Origins of H and S geometries */
};
@@ -426,7 +409,8 @@ struct dosemu_header {
#define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d))
-static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
+static const struct geometry *get_disk_image_geometry(uint32_t where,
+ uint32_t size)
{
static struct geometry hd_geometry;
struct dosemu_header dosemu;
@@ -437,6 +421,8 @@ static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t s
printf("command line: %s\n", shdr->cmdline);
+ hd_geometry.sector_size = 512; /* Assume floppy/HDD at first */
+
offset = 0;
if (CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)))
offset = v;
@@ -448,6 +434,74 @@ static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t s
hd_geometry.sectors = sectors;
hd_geometry.offset = offset;
+ if ((p = getcmditem("iso")) != CMD_NOTFOUND) {
+#ifdef DBG_ELTORITO
+ eltorito_dump(where);
+#endif
+ struct edd4_bvd *bvd = (struct edd4_bvd *)(where + 17 * 2048);
+ /* Tiny sanity check */
+ if ((bvd->boot_rec_ind != 0) || (bvd->ver != 1))
+ printf("El Torito BVD sanity check failed.\n");
+ struct edd4_bootcat *boot_cat =
+ (struct edd4_bootcat *)(where + bvd->boot_cat * 2048);
+ /* Another tiny sanity check */
+ if ((boot_cat->validation_entry.platform_id != 0) ||
+ (boot_cat->validation_entry.key55 != 0x55) ||
+ (boot_cat->validation_entry.keyAA != 0xAA))
+ printf("El Torito boot catalog sanity check failed.\n");
+ /* If we have an emulation mode, set the offset to the image */
+ if (boot_cat->initial_entry.media_type)
+ hd_geometry.offset += boot_cat->initial_entry.load_block * 2048;
+ else
+ /* We're a no-emulation mode, so we will boot to an offset */
+ hd_geometry.boot_lba = boot_cat->initial_entry.load_block * 4;
+ if (boot_cat->initial_entry.media_type < 4) {
+ /* We're a floppy emulation mode or our params will be
+ * overwritten by the no emulation mode case
+ */
+ hd_geometry.driveno = 0x00;
+ hd_geometry.c = 80;
+ hd_geometry.h = 2;
+ }
+ switch (boot_cat->initial_entry.media_type) {
+ case 0: /* No emulation */
+ hd_geometry.driveno = 0xE0;
+ hd_geometry.type = 10; /* ATAPI removable media device */
+ hd_geometry.c = 65535;
+ hd_geometry.h = 255;
+ hd_geometry.s = 15;
+ /* 2048-byte sectors, so adjust the size and count */
+ hd_geometry.sector_size = 2048;
+ sectors = (size - hd_geometry.offset) >> 11;
+ break;
+ case 1: /* 1.2 MB floppy */
+ hd_geometry.s = 15;
+ hd_geometry.type = 2;
+ sectors = 2400;
+ break;
+ case 2: /* 1.44 MB floppy */
+ hd_geometry.s = 18;
+ hd_geometry.type = 4;
+ sectors = 2880;
+ break;
+ case 3: /* 2.88 MB floppy */
+ hd_geometry.s = 36;
+ hd_geometry.type = 6;
+ sectors = 5760;
+ break;
+ case 4:
+ hd_geometry.driveno = 0x80;
+ hd_geometry.type = 0;
+ sectors = (size - hd_geometry.offset) >> 9;
+ break;
+ }
+ /* For HDD emulation, we figure out the geometry later. Otherwise: */
+ if (hd_geometry.s) {
+ hd_geometry.hsrc = hd_geometry.ssrc = "El Torito";
+ }
+ hd_geometry.sectors = sectors;
+ }
+
/* Do we have a DOSEMU header? */
memcpy(&dosemu, (char *)where + hd_geometry.offset, sizeof dosemu);
if (!memcmp("DOSEMU", dosemu.magic, 7)) {
@@ -511,7 +565,7 @@ static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t s
if (!(max_h | max_s)) {
/* No FAT filesystem found to steal geometry from... */
- if (sectors < 4096 * 2) {
+ if ((sectors < 4096 * 2) && (hd_geometry.sector_size == 512)) {
int ok = 0;
unsigned int xsectors = sectors;
@@ -572,7 +626,9 @@ static const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t s
const struct ptab_entry *ptab = (const struct ptab_entry *)
((char *)where + hd_geometry.offset + (512 - 2 - 4 * 16));
- hd_geometry.driveno = 0x80; /* Assume hard disk */
+ /* Assume hard disk */
+ if (!hd_geometry.driveno)
+ hd_geometry.driveno = 0x80;
if (*(uint16_t *) ((char *)where + 512 - 2) == 0xaa55) {
for (i = 0; i < 4; i++) {
@@ -674,46 +730,46 @@ static uint32_t pnp_install_check(void)
struct gdt_ptr {
uint16_t limit;
uint32_t base;
-} __attribute__((packed));
+} __attribute__ ((packed));
static void set_seg_base(uint32_t gdt_base, int seg, uint32_t v)
{
- *(uint16_t *)(gdt_base + seg + 2) = v;
- *(uint8_t *)(gdt_base + seg + 4) = v >> 16;
- *(uint8_t *)(gdt_base + seg + 7) = v >> 24;
+ *(uint16_t *) (gdt_base + seg + 2) = v;
+ *(uint8_t *) (gdt_base + seg + 4) = v >> 16;
+ *(uint8_t *) (gdt_base + seg + 7) = v >> 24;
}
static void relocate_rm_code(uint32_t newbase)
{
uint32_t gdt_base;
uint32_t oldbase = rm_args.rm_base;
- uint32_t delta = newbase - oldbase;
+ uint32_t delta = newbase - oldbase;
cli();
memmove((void *)newbase, (void *)oldbase, rm_args.rm_size);
- rm_args.rm_return += delta;
- rm_args.rm_intcall += delta;
- rm_args.rm_bounce += delta;
- rm_args.rm_base += delta;
- rm_args.rm_gdt += delta;
- rm_args.rm_pmjmp += delta;
- rm_args.rm_rmjmp += delta;
+ rm_args.rm_return += delta;
+ rm_args.rm_intcall += delta;
+ rm_args.rm_bounce += delta;
+ rm_args.rm_base += delta;
+ rm_args.rm_gdt += delta;
+ rm_args.rm_pmjmp += delta;
+ rm_args.rm_rmjmp += delta;
gdt_base = rm_args.rm_gdt;
- *(uint32_t *)(gdt_base+2) = gdt_base; /* GDT self-pointer */
+ *(uint32_t *) (gdt_base + 2) = gdt_base; /* GDT self-pointer */
/* Segments 0x10 and 0x18 are real-mode-based */
set_seg_base(gdt_base, 0x10, rm_args.rm_base);
set_seg_base(gdt_base, 0x18, rm_args.rm_base);
- asm volatile("lgdtl %0" : : "m" (*(char *)gdt_base));
+ asm volatile ("lgdtl %0"::"m" (*(char *)gdt_base));
- *(uint32_t *)rm_args.rm_pmjmp += delta;
- *(uint16_t *)rm_args.rm_rmjmp += delta >> 4;
+ *(uint32_t *) rm_args.rm_pmjmp += delta;
+ *(uint16_t *) rm_args.rm_rmjmp += delta >> 4;
- rm_args.rm_handle_interrupt += delta;
+ rm_args.rm_handle_interrupt += delta;
sti();
}
@@ -768,15 +824,17 @@ void setup(const struct real_mode_args *rm_args_ptr)
const struct geometry *geometry;
unsigned int total_size;
unsigned int cmdline_len, stack_len, e820_len;
+ const struct edd4_bvd *bvd;
+ const struct edd4_bootcat *boot_cat = 0;
com32sys_t regs;
uint32_t ramdisk_image, ramdisk_size;
uint32_t boot_base, rm_base;
int bios_drives;
int do_edd = 1; /* 0 = no, 1 = yes, default is yes */
+ int do_eltorito = 0; /* default is no */
int no_bpt; /* No valid BPT presented */
uint32_t boot_seg = 0; /* Meaning 0000:7C00 */
uint32_t boot_len = 512; /* One sector */
- uint32_t boot_lba = 0; /* LBA of bootstrap code */
/* We need to copy the rm_args into their proper place */
memcpy(&rm_args, rm_args_ptr, sizeof rm_args);
@@ -811,13 +869,28 @@ void setup(const struct real_mode_args *rm_args_ptr)
else
do_edd = (geometry->driveno & 0x80) ? 1 : 0;
+ if (getcmditem("iso") != CMD_NOTFOUND) {
+ do_eltorito = 1;
+ do_edd = 1; /* Mandatory */
+ }
+
/* Choose the appropriate installable memdisk hook */
- if (do_edd) {
- bin_size = (int)&_binary_memdisk_edd_bin_size;
- memdisk_hook = (char *)&_binary_memdisk_edd_bin_start;
+ if (do_eltorito) {
+ if (geometry->sector_size == 2048) {
+ bin_size = (int)&_binary_memdisk_iso_2048_bin_size;
+ memdisk_hook = (char *)&_binary_memdisk_iso_2048_bin_start;
+ } else {
+ bin_size = (int)&_binary_memdisk_iso_512_bin_size;
+ memdisk_hook = (char *)&_binary_memdisk_iso_512_bin_start;
+ }
} else {
- bin_size = (int)&_binary_memdisk_chs_bin_size;
- memdisk_hook = (char *)&_binary_memdisk_chs_bin_start;
+ if (do_edd) {
+ bin_size = (int)&_binary_memdisk_edd_512_bin_size;
+ memdisk_hook = (char *)&_binary_memdisk_edd_512_bin_start;
+ } else {
+ bin_size = (int)&_binary_memdisk_chs_512_bin_size;
+ memdisk_hook = (char *)&_binary_memdisk_chs_512_bin_start;
+ }
}
/* Reserve the ramdisk memory */
@@ -837,7 +910,7 @@ void setup(const struct real_mode_args *rm_args_ptr)
pptr->driveno = geometry->driveno;
pptr->drivetype = geometry->type;
- pptr->cylinders = geometry->c;
+ pptr->cylinders = geometry->c; /* Possible precision loss */
pptr->heads = geometry->h;
pptr->sectors = geometry->s;
pptr->disksize = geometry->sectors;
@@ -933,16 +1006,37 @@ void setup(const struct real_mode_args *rm_args_ptr)
pptr->edd_dpt.c = geometry->c;
pptr->edd_dpt.h = geometry->h;
pptr->edd_dpt.s = geometry->s;
- pptr->edd_dpt.flags |= 0x0002; /* Geometry valid */
+ /* EDD-4 states that invalid geometry should be returned
+ * for INT 0x13, AH=0x48 "EDD Get Disk Parameters" call on an
+ * El Torito ODD. Check for 2048-byte sector size
+ */
+ if (geometry->sector_size != 2048)
+ pptr->edd_dpt.flags |= 0x0002; /* Geometry valid */
}
if (!(geometry->driveno & 0x80)) {
/* Floppy drive. Mark it as a removable device with
media change notification; media is present. */
pptr->edd_dpt.flags |= 0x0014;
}
-
+
pptr->edd_dpt.devpath[0] = pptr->diskbuf;
- pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73-30);
+ pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73 - 30);
+ }
+
+ if (do_eltorito) {
+ bvd = (struct edd4_bvd *)(ramdisk_image + 17 * 2048);
+ boot_cat =
+ (struct edd4_bootcat *)(ramdisk_image + bvd->boot_cat * 2048);
+ pptr->cd_pkt.type = boot_cat->initial_entry.media_type; /* Cheat */
+ pptr->cd_pkt.driveno = geometry->driveno;
+ pptr->cd_pkt.start = boot_cat->initial_entry.load_block;
+ boot_seg = pptr->cd_pkt.load_seg = boot_cat->initial_entry.load_seg;
+ pptr->cd_pkt.sect_count = boot_cat->initial_entry.sect_count;
+ boot_len = pptr->cd_pkt.sect_count * 512;
+ pptr->cd_pkt.geom1 = (uint8_t)(pptr->cylinders) & 0xFF;
+ pptr->cd_pkt.geom2 =
+ (uint8_t)(pptr->sectors) | (uint8_t)((pptr->cylinders >> 2) & 0xC0);
+ pptr->cd_pkt.geom3 = (uint8_t)(pptr->heads);
}
/* The size is given by hptr->total_size plus the size of the E820
@@ -1059,6 +1153,13 @@ void setup(const struct real_mode_args *rm_args_ptr)
if (pptr->drivecnt <= (geometry->driveno & 0x7f))
pptr->drivecnt = (geometry->driveno & 0x7f) + 1;
+ /* Probe for contiguous range of BIOS drives starting with driveno */
+ pptr->driveshiftlimit = probe_drive_range(geometry->driveno) + 1;
+ if ((pptr->driveshiftlimit & 0x80) != (geometry->driveno & 0x80))
+ printf("We lost the last drive in our class of drives.\n");
+ printf("Drive probing gives drive shift limit: 0x%02x\n",
+ pptr->driveshiftlimit);
+
/* Pointer to the command line */
pptr->cmdline_off = bin_size + (nranges + 1) * sizeof(ranges[0]);
pptr->cmdline_seg = driverseg;
@@ -1087,7 +1188,7 @@ void setup(const struct real_mode_args *rm_args_ptr)
if (nhd > 128)
nhd = 128;
- wrz_8(BIOS_HD_COUNT, nhd);
+ if (!do_eltorito) wrz_8(BIOS_HD_COUNT, nhd);
} else {
/* Update BIOS floppy disk count */
uint8_t equip = rdz_8(BIOS_EQUIP);
@@ -1124,11 +1225,11 @@ void setup(const struct real_mode_args *rm_args_ptr)
/* Figure out entry point */
if (!boot_seg) {
- boot_base = 0x7c00;
- shdr->sssp = 0x7c00;
- shdr->csip = 0x7c00;
+ boot_base = 0x7c00;
+ shdr->sssp = 0x7c00;
+ shdr->csip = 0x7c00;
} else {
- boot_base = boot_seg << 4;
+ boot_base = boot_seg << 4;
shdr->sssp = boot_seg << 16;
shdr->csip = boot_seg << 16;
}
@@ -1143,7 +1244,8 @@ void setup(const struct real_mode_args *rm_args_ptr)
/* Reboot into the new "disk" */
puts("Loading boot sector... ");
- memcpy((void *)boot_base, (char *)pptr->diskbuf + boot_lba*512, boot_len);
+ memcpy((void *)boot_base, (char *)pptr->diskbuf + geometry->boot_lba * 512,
+ boot_len);
if (getcmditem("pause") != CMD_NOTFOUND) {
puts("press any key to boot... ");
@@ -1155,5 +1257,5 @@ void setup(const struct real_mode_args *rm_args_ptr)
/* On return the assembly code will jump to the boot vector */
shdr->esdi = pnp_install_check();
- shdr->edx = geometry->driveno;
+ shdr->edx = geometry->driveno;
}
diff --git a/utils/isohybrid.in b/utils/isohybrid.in
index 0726bed9..a1277848 100644
--- a/utils/isohybrid.in
+++ b/utils/isohybrid.in
@@ -221,7 +221,7 @@ $mbr .= "\0\0"; # Offset 446: actual partition table
# Print partition table
$offset = $opt{'offset'};
-$psize = $c*$h*$s;
+$psize = $c*$h*$s - $offset;
$bhead = int($offset/$s) % $h;
$bsect = ($offset % $s) + 1;
$bcyl = int($offset/($h*$s));
@@ -236,7 +236,7 @@ $pentry = $opt{'entry'}; # Partition slot
for ( $i = 1 ; $i <= 4 ; $i++ ) {
if ( $i == $pentry ) {
$mbr .= pack("CCCCCCCCVV", 0x80, $bhead, $bsect, $bcyl, $fstype,
- $ehead, $esect, $ecyl, 0, $psize);
+ $ehead, $esect, $ecyl, $offset, $psize);
} else {
$mbr .= "\0" x 16;
}
diff --git a/version b/version
index f2649fb3..93edd122 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-3.83 2009
+3.84 2009