diff options
| author | H. Peter Anvin <hpa@zytor.com> | 2009-05-19 16:30:09 -0700 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2009-05-19 16:30:09 -0700 |
| commit | 0fa4369624b4637a7e36ed22e89a759031f08327 (patch) | |
| tree | 4aa1cf5c87d36153cee3c727d5f77498c0042983 /dos/syslinux.c | |
| parent | c9ad266f64f9ee81a859bdf70c1190ee0cc1bc19 (diff) | |
| download | syslinux-0fa4369624b4637a7e36ed22e89a759031f08327.tar.gz | |
FAT: change DOS installer to EXE; additional 32K limit fixes
Additional fixes for the 32K limits in the installers. In the case
of the DOS installer, that means changing it from COM format to EXE
format (since COM format has a 63K hard limit); retain the name
syslinux.com for user compatibility, though (DOS doesn't care what the
extension except for pathname search; if it finds an MZ EXE header it
will use it.)
With the change to EXE means having to handle more than one segment.
Since we don't have a real DOS compiler we have to wing it a bit.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'dos/syslinux.c')
| -rw-r--r-- | dos/syslinux.c | 63 |
1 files changed, 54 insertions, 9 deletions
diff --git a/dos/syslinux.c b/dos/syslinux.c index 064859f7..047dc8f8 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -114,6 +114,35 @@ int rename(const char *oldname, const char *newname) return 0; } +extern const char __payload_sseg[]; +static uint16_t ldlinux_seg; + +ssize_t write_ldlinux(int fd) +{ + uint32_t offset = 0; + uint16_t rv; + uint8_t err; + + while (offset < syslinux_ldlinux_len) { + uint32_t chunk = syslinux_ldlinux_len - offset; + if (chunk > 32768) + chunk = 32768; + asm volatile("pushw %%ds ; " + "movw %6,%%ds ; " + "int $0x21 ; " + "popw %%ds ; " + "setc %0" + : "=bcdm" (err), "=a" (rv) + : "a" (0x4000), "b" (fd), "c" (chunk), "d" (offset & 15), + "SD" ((uint16_t)(ldlinux_seg + (offset >> 4)))); + if ( err || rv == 0 ) + die("file write error"); + offset += rv; + } + + return offset; +} + ssize_t write_file(int fd, const void *buf, size_t count) { uint16_t rv; @@ -123,10 +152,9 @@ ssize_t write_file(int fd, const void *buf, size_t count) dprintf("write_file(%d,%p,%u)\n", fd, buf, count); while ( count ) { - rv = 0x4000; asm volatile("int $0x21 ; setc %0" - : "=abcdm" (err), "+a" (rv) - : "b" (fd), "c" (count), "d" (buf)); + : "=bcdm" (err), "=a" (rv) + : "a" (0x4000), "b" (fd), "c" (count), "d" (buf)); if ( err || rv == 0 ) die("file write error"); @@ -480,7 +508,9 @@ int main(int argc, char *argv[]) char **argp, *opt; int force = 0; /* -f (force) option */ struct libfat_filesystem *fs; - libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ + libfat_sector_t s, *secp; + libfat_sector_t *sectors; + int ldlinux_sectors; int32_t ldlinux_cluster; int nsectors; const char *device = NULL, *bootsecfile = NULL; @@ -491,6 +521,9 @@ int main(int argc, char *argv[]) const char *subdir = NULL; int stupid = 0; int raid_mode = 0; + int patch_sectors; + + ldlinux_seg = (size_t)__payload_sseg + data_segment(); dprintf("argv = %p\n", argv); for ( i = 0 ; i <= argc ; i++ ) @@ -572,7 +605,7 @@ int main(int argc, char *argv[]) set_attributes(ldlinux_name, 0); fd = creat(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */ - write_file(fd, syslinux_ldlinux, syslinux_ldlinux_len); + write_ldlinux(fd); close(fd); /* @@ -581,13 +614,15 @@ int main(int argc, char *argv[]) * this is supposed to be a simple, privileged version * of the installer. */ + ldlinux_sectors = (syslinux_ldlinux_len+SECTOR_SIZE-1) >> SECTOR_BITS; + sectors = calloc(ldlinux_sectors, sizeof *sectors); lock_device(2); fs = libfat_open(libfat_xpread, dev_fd); ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); secp = sectors; nsectors = 0; s = libfat_clustertosector(fs, ldlinux_cluster); - while ( s && nsectors < 65 ) { + while ( s && nsectors < ldlinux_sectors ) { *secp++ = s; nsectors++; s = libfat_nextsector(fs, s); @@ -640,13 +675,23 @@ int main(int argc, char *argv[]) /* * Patch ldlinux.sys and the boot sector */ - syslinux_patch(sectors, nsectors, stupid, raid_mode); + i = syslinux_patch(sectors, nsectors, stupid, raid_mode); + patch_sectors = (i + 511) >> 9; /* - * Write the now-patched first sector of ldlinux.sys + * Overwrite the now-patched ldlinux.sys */ lock_device(3); - write_device(dev_fd, syslinux_ldlinux, 1, sectors[0]); + for (i = 0; i < patch_sectors; i++) { + uint16_t si, di, cx; + si = 0; + di = (size_t)sectbuf; + cx = 512 >> 2; + asm volatile("movw %3,%%fs ; fs ; rep ; movsl" + : "+S" (si), "+D" (di), "+c" (cx) + : "abd" ((uint16_t)(ldlinux_seg + (i << (9-4))))); + write_device(dev_fd, sectbuf, 1, sectors[i]); + } /* * Muck with the MBR, if desired, while we hold the lock |
