diff options
author | Erwan Velu <erwan.velu@free.fr> | 2009-11-20 23:14:00 +0100 |
---|---|---|
committer | Erwan Velu <erwan.velu@free.fr> | 2009-11-20 23:14:00 +0100 |
commit | 900d7a87216346fedc7af7425ed711b6979fec4b (patch) | |
tree | e7b03aa43a9e43a2775cd5cde36e6ea64980b8c1 | |
parent | b417dc2763b6009a3b823f229b931f1847982826 (diff) | |
parent | a0dae108231cdd929aff1f6551fcb70c806c0f99 (diff) | |
download | syslinux-900d7a87216346fedc7af7425ed711b6979fec4b.tar.gz |
Merge remote branch 'hpa/master'
36 files changed, 1342 insertions, 192 deletions
@@ -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, ®s, ®s); 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(®s, 0, sizeof regs); + + regs.eax.b[1] = probe; /* AH = probe */ + regs.edx.b[0] = drive; /* DL = drive number to probe */ + intcall(0x13, ®s, ®s); + + 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; } @@ -1 +1 @@ -3.83 2009 +3.84 2009 |