[syslinux:pathbased] Reduce sector 1 space pressure; further merge installer code

syslinux-bot for H. Peter Anvin hpa at zytor.com
Sun Jun 20 15:24:20 PDT 2010


Commit-ID:  8cf2a1fb42a61f6d19afee86f52ff260fabd1cfa
Gitweb:     http://syslinux.zytor.com/commit/8cf2a1fb42a61f6d19afee86f52ff260fabd1cfa
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Sun, 20 Jun 2010 15:21:05 -0700
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Sun, 20 Jun 2010 15:21:05 -0700

Reduce sector 1 space pressure; further merge installer code

Reduce sector 1 space pressure by moving objects that aren't needed by
Sector 1 proper into an "extended patch area".  While we're mucking
with the installer code, make the syslxint and extlinux installer code
even more similar.  It should now be pretty straightforward to
outright merge the code.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 core/diskstart.inc      |   36 +++++++----
 dos/Makefile            |    2 +-
 dos/getsetsl.c          |  100 +++++++++++++++++++++++++++++
 extlinux/main.c         |  127 ++++++++++++++++++++-----------------
 libinstaller/syslxint.h |   77 +++++++++++++++++++---
 libinstaller/syslxmod.c |  162 +++++++++-------------------------------------
 6 files changed, 294 insertions(+), 210 deletions(-)

diff --git a/core/diskstart.inc b/core/diskstart.inc
index d858c35..c21c9e2 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -235,8 +235,10 @@ eddcheck:
 ; with parsing the superblock and root directory; it doesn't fit
 ; together with EBIOS support, unfortunately.
 ;
-		mov eax,[FirstSector]	; Sector start
-		mov edx,[FirstSector+4]
+		mov eax,strict dword 0xdeadbeef
+Sect1Ptr0	equ $-4
+		mov edx,strict dword 0xfeedface
+Sect1Ptr1	equ $-4
 		mov bx,ldlinux_sys	; Where to load it
 		call getonesec
 
@@ -404,13 +406,9 @@ xint13:
 bailmsg:	db 'Boot error', 0Dh, 0Ah, 0
 
 		; This fails if the boot sector overflowsg
-		zb 1F6h-($-$$)
-FirstSector	dq 0xFEEDFACEDEADBEEF		; Location of sector 1
+		zb 1FEh-($-$$)
 
-; This field will be filled in 0xAA55 by the installer, but we abuse it
-; to house a pointer to the INT 16h instruction at
-; kaboom.again, which gets patched to INT 18h in RAID mode.
-bootsignature	dw kaboom.again-bootsec
+bootsignature	dw 0xAA55
 
 ;
 ; ===========================================================================
@@ -443,6 +441,15 @@ LDLDwords	dd 0		; Total dwords starting at ldlinux_sys,
 CheckSum	dd 0		; Checksum starting at ldlinux_sys
 				; value = LDLINUX_MAGIC - [sum of dwords]
 MaxTransfer	dw 127		; Max sectors to transfer
+EPAPtr		dw EPA - LDLINUX_SYS	; Pointer to the extended patch area
+
+;
+; Extended patch area -- this is in .data16 so it doesn't occupy space in
+; the first sector.  Use this structure for anything that isn't used by
+; the first sector itself.
+;
+		section .data16
+EPA:
 ADVSecPtr	dw ADVSec0 - LDLINUX_SYS
 CurrentDirPtr	dw CurrentDirName-LDLINUX_SYS	; Current directory name string
 CurrentDirLen	dw CURRENTDIR_MAX
@@ -452,16 +459,21 @@ SecPtrOffset	dw SectorPtrs-LDLINUX_SYS
 SecPtrCnt	dw (SectorPtrsEnd - SectorPtrs)/10
 
 ;
-; Installer pokes the base directory here.  This is in .data16 so it
-; isn't actually located in the first sector.
+; Boot sector patch pointers
+;
+Sect1Ptr0Ptr	dw Sect1Ptr0 - bootsec		; Pointers to Sector 1 location
+Sect1Ptr1Ptr	dw Sect1Ptr1 - bootsec
+RAIDPatchPtr	dw kaboom.again - bootsec	; Patch to INT 18h in RAID mode
+
+;
+; Base directory name and subvolume, if applicable.
 ;
 %define HAVE_CURRENTDIRNAME
-		section .data16
 		global CurrentDirName, SubvolName
 CurrentDirName	times CURRENTDIR_MAX db 0
 SubvolName	times SUBVOL_MAX db 0
-		section .init
 
+		section .init
 ldlinux_ent:
 ;
 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
diff --git a/dos/Makefile b/dos/Makefile
index fbaca6b..7392571 100644
--- a/dos/Makefile
+++ b/dos/Makefile
@@ -33,7 +33,7 @@ SRCS     = syslinux.c \
            $(wildcard ../libfat/*.c)
 OBJS	 = header.o crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS)))
 LIBOBJS	 = int2526.o conio.o memcpy.o memset.o  skipatou.o atou.o \
-	   malloc.o free.o \
+	   malloc.o free.o getsetsl.o \
 	   argv.o printf.o __divdi3.o __udivmoddi4.o
 
 VPATH = .:../libfat:../libinstaller
diff --git a/dos/getsetsl.c b/dos/getsetsl.c
new file mode 100644
index 0000000..a48f3df
--- /dev/null
+++ b/dos/getsetsl.c
@@ -0,0 +1,100 @@
+/*
+ * Special handling for the MS-DOS derivative: syslinux_ldlinux
+ * is a "far" object...
+ */
+
+#define _XOPEN_SOURCE 500	/* Required on glibc 2.x */
+#define _BSD_SOURCE
+#include <inttypes.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "syslxint.h"
+
+#define __noinline __attribute__((noinline))
+
+#if 0				/* unused */
+uint8_t get_8_sl(const uint8_t * p)
+{
+    uint8_t v;
+
+    p = set_fs(p);
+    asm volatile("movb %%fs:%1,%0":"=q" (v):"m"(*p));
+    return v;
+}
+#endif
+
+uint16_t get_16_sl(const uint16_t * p)
+{
+    uint16_t v;
+
+    p = set_fs(p);
+    asm volatile("movw %%fs:%1,%0":"=r" (v):"m"(*p));
+    return v;
+}
+
+uint32_t get_32_sl(const uint32_t * p)
+{
+    uint32_t v;
+
+    p = set_fs(p);
+    asm volatile("movl %%fs:%1,%0":"=r" (v):"m"(*p));
+    return v;
+}
+
+#if 0				/* unused */
+uint64_t get_64_sl(const uint64_t * p)
+{
+    uint32_t v0, v1;
+    const uint32_t *pp = (const uint32_t *)set_fs(p);
+
+    asm volatile("movl %%fs:%1,%0" : "=r" (v0) : "m" (pp[0]));
+    asm volatile("movl %%fs:%1,%0" : "=r" (v1) : "m" (pp[1]));
+    return v0 + ((uint64_t)v1 << 32);
+}
+#endif
+
+#if 0				/* unused */
+void set_8_sl(uint8_t * p, uint8_t v)
+{
+    p = set_fs(p);
+    asm volatile("movb %1,%%fs:%0":"=m" (*p):"qi"(v));
+}
+#endif
+
+void set_16_sl(uint16_t * p, uint16_t v)
+{
+    p = set_fs(p);
+    asm volatile("movw %1,%%fs:%0":"=m" (*p):"ri"(v));
+}
+
+void set_32_sl(uint32_t * p, uint32_t v)
+{
+    p = set_fs(p);
+    asm volatile("movl %1,%%fs:%0":"=m" (*p):"ri"(v));
+}
+
+void set_64_sl(uint64_t * p, uint64_t v)
+{
+    uint32_t *pp = (uint32_t *)set_fs(p);
+    asm volatile("movl %1,%%fs:%0" : "=m" (pp[0]) : "ri"((uint32_t)v));
+    asm volatile("movl %1,%%fs:%0" : "=m" (pp[1]) : "ri"((uint32_t)(v >> 32)));
+}
+
+void memcpy_to_sl(void *dst, const void *src, size_t len)
+{
+    uint16_t seg;
+    uint16_t off;
+
+    seg = ldlinux_seg + ((size_t)dst >> 4);
+    off = (size_t)dst & 15;
+
+    asm volatile("pushw %%es ; "
+		 "movw %3,%%es ; "
+		 "rep ; movsb ; "
+		 "popw %%es"
+		 : "+D" (off), "+S" (src), "+c" (len)
+		 : "r" (seg)
+		 : "memory");
+}
diff --git a/extlinux/main.c b/extlinux/main.c
index 6ce3b60..cf9840d 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -210,8 +210,8 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs,
 	}
 
 	if (len) {
-	    set_64(&ex->lba, lba);
-	    set_16(&ex->len, len);
+	    set_64_sl(&ex->lba, lba);
+	    set_16_sl(&ex->len, len);
 	    ex++;
 	}
 
@@ -225,13 +225,21 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs,
     }
 
     if (len) {
-	set_64(&ex->lba, lba);
-	set_16(&ex->len, len);
+	set_64_sl(&ex->lba, lba);
+	set_16_sl(&ex->len, len);
 	ex++;
     }
 }
 
 /*
+ * Form a pointer based on a 16-bit patcharea/epa field
+ */
+static inline void *ptr(void *img, uint16_t *offset_p)
+{
+    return (char *)img + get_16_sl(offset_p);
+}
+
+/*
  * Query the device geometry and put it into the boot sector.
  * Map the file and put the map in the boot sector and file.
  * Stick the "current directory" inode number into the file.
@@ -246,12 +254,12 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
     uint64_t totalbytes, totalsectors;
     int nsect;
     uint32_t *wp;
-    struct boot_sector *bs;
+    struct boot_sector *sbs;
     struct patch_area *patcharea;
+    struct ext_patch_area *epa;
     struct syslinux_extent *ex;
     int i, dw, nptrs;
     uint32_t csum;
-    int secptroffset, diroffset, dirlen, subvoloffset, subvollen;
     char *dirpath, *subpath, *xdirpath, *xsubpath;
     uint64_t *advptrs;
 
@@ -310,28 +318,20 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
        early bootstrap share code with the FAT version. */
     dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
 
-    bs = (struct boot_sector *)boot_block;
+    sbs = (struct boot_sector *)boot_block;
 
     totalsectors = totalbytes >> SECTOR_SHIFT;
     if (totalsectors >= 65536) {
-	set_16(&bs->bsSectors, 0);
+	set_16(&sbs->bsSectors, 0);
     } else {
-	set_16(&bs->bsSectors, totalsectors);
+	set_16(&sbs->bsSectors, totalsectors);
     }
-    set_32(&bs->bsHugeSectors, totalsectors);
+    set_32(&sbs->bsHugeSectors, totalsectors);
 
-    set_16(&bs->bsBytesPerSec, SECTOR_SIZE);
-    set_16(&bs->bsSecPerTrack, geo.sectors);
-    set_16(&bs->bsHeads, geo.heads);
-    set_32(&bs->bsHiddenSecs, geo.start);
-
-    /* If we're in RAID mode then patch the appropriate instruction;
-       either way write the proper boot signature */
-    i = get_16(&bs->bsSignature);
-    if (opt.raid_mode)
-	set_16((uint16_t *) (boot_block + i), 0x18CD);	/* INT 18h */
-
-    set_16(&bs->bsSignature, 0xAA55);
+    set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
+    set_16(&sbs->bsSecPerTrack, geo.sectors);
+    set_16(&sbs->bsHeads, geo.heads);
+    set_32(&sbs->bsHiddenSecs, geo.start);
 
     /* Construct the boot file */
 
@@ -351,27 +351,39 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
 		*(sectp + i) = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
     }
 
-    /* First sector need pointer in boot sector */
-    set_64(&bs->NextSector, *sectp++);
-
     /* Search for LDLINUX_MAGIC to find the patch area */
-    for (wp = (uint32_t *) boot_image; get_32(wp) != LDLINUX_MAGIC; wp++) ;
+    for (wp = (uint32_t *) boot_image; get_32_sl(wp) != LDLINUX_MAGIC;
+	 wp++)
+	;
     patcharea = (struct patch_area *)wp;
+    epa = ptr(boot_image, &patcharea->epaoffset);
+
+    /* First sector need pointer in boot sector */
+    set_32(ptr(sbs, &epa->sect1ptr0), sectp[0]);
+    set_32(ptr(sbs, &epa->sect1ptr1), sectp[0] >> 32);
+    sectp++;
+
+    /* Handle RAID mode */
+    if (opt.raid_mode) {
+	/* Patch in INT 18h = CD 18 */
+	set_16(ptr(sbs, &epa->raidpatch), 0x18CD);
+    }
 
     /* Set up the totals */
     dw = boot_image_len >> 2;	/* COMPLETE dwords, excluding ADV */
-    set_16(&patcharea->data_sectors, nsect - 2);	/* -2 for the ADVs */
-    set_16(&patcharea->adv_sectors, 2);
-    set_32(&patcharea->dwords, dw);
+    set_16_sl(&patcharea->data_sectors, nsect - 2); /* Not including ADVs */
+    set_16_sl(&patcharea->adv_sectors, 2);	/* ADVs need 2 sectors */
+    set_32_sl(&patcharea->dwords, dw);
 
     /* Stupid mode? */
-    if (opt.stupid_mode)
-	set_16(&patcharea->maxtransfer, 1);
+    if (opt.stupid_mode) {
+	/* Access only one sector at a time */
+	set_16_sl(&patcharea->maxtransfer, 1);
+    }
 
     /* Set the sector extents */
-    secptroffset = get_16(&patcharea->secptroffset);
-    ex = (struct syslinux_extent *) ((char *)boot_image + secptroffset);
-    nptrs = get_16(&patcharea->secptrcnt);
+    ex = ptr(boot_image, &epa->secptroffset);
+    nptrs = get_16_sl(&epa->secptrcnt);
 
     if (nsect > nptrs) {
 	/* Not necessarily an error in this case, but a general problem */
@@ -383,38 +395,39 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
     generate_extents(ex, nptrs, sectp, nsect-1-2);
 
     /* ADV pointers */
-    advptrs = (uint64_t *)((char *)boot_image +
-			   get_16(&patcharea->advptroffset));
-    set_64(&advptrs[0], sectp[nsect-1-2]);
-    set_64(&advptrs[1], sectp[nsect-1-1]);
+    advptrs = ptr(boot_image, &epa->advptroffset);
+    set_64_sl(&advptrs[0], sectp[nsect-1-2]);
+    set_64_sl(&advptrs[1], sectp[nsect-1-1]);
 
     /* Poke in the base directory path */
-    diroffset = get_16(&patcharea->diroffset);
-    dirlen = get_16(&patcharea->dirlen);
-    if (dirlen <= strlen(subpath)) {
-	fprintf(stderr, "Subdirectory path too long... aborting install!\n");
-	exit(1);
+    if (subpath) {
+	int sublen = strlen(subpath) + 1;
+	if (get_16_sl(&epa->dirlen) < sublen) {
+	    fprintf(stderr, "Subdirectory path too long... aborting install!\n");
+	    exit(1);
+	}
+	memcpy_to_sl(ptr(boot_image, &epa->diroffset), subpath, sublen);
     }
-    strncpy((char *)boot_image + diroffset, subpath, dirlen);
     free(dirpath);
 
-    /* write subvol info if we have */
-    subvoloffset = get_16(&patcharea->subvoloffset);
-    subvollen = get_16(&patcharea->subvollen);
-    if (subvollen <= strlen(subvol)) {
-	fprintf(stderr, "Subvol name too long... aborting install!\n");
-	exit(1);
+    /* Poke in the subvolume information */
+    if (1 /* subvol */) {
+	int sublen = strlen(subvol) + 1;
+	if (get_16_sl(&epa->subvollen) < sublen) {
+	    fprintf(stderr, "Subvol name too long... aborting install!\n");
+	    exit(1);
+	}
+	memcpy_to_sl(ptr(boot_image, &epa->subvoloffset), subvol, sublen);
     }
-    strncpy((char *)boot_image + subvoloffset, subvol, subvollen);
 
     /* Now produce a checksum */
-    set_32(&patcharea->checksum, 0);
+    set_32_sl(&patcharea->checksum, 0);
 
     csum = LDLINUX_MAGIC;
     for (i = 0, wp = (uint32_t *) boot_image; i < dw; i++, wp++)
-	csum -= get_32(wp);	/* Negative checksum */
+	csum -= get_32_sl(wp);	/* Negative checksum */
 
-    set_32(&patcharea->checksum, csum);
+    set_32_sl(&patcharea->checksum, csum);
 
     /*
      * Assume all bytes modified.  This can be optimized at the expense
@@ -490,9 +503,9 @@ int install_bootblock(int fd, const char *device)
 	return 1;
     }
     if (fs_type == VFAT) {
-	struct boot_sector *bs = (struct boot_sector *)extlinux_bootsect;
-        if (xpwrite(fd, &bs->bsHead, bsHeadLen, 0) != bsHeadLen ||
-	    xpwrite(fd, &bs->bsCode, bsCodeLen,
+	struct boot_sector *sbs = (struct boot_sector *)extlinux_bootsect;
+        if (xpwrite(fd, &sbs->bsHead, bsHeadLen, 0) != bsHeadLen ||
+	    xpwrite(fd, &sbs->bsCode, bsCodeLen,
 		    offsetof(struct boot_sector, bsCode)) != bsCodeLen) {
 	    perror("writing fat bootblock");
 	    return 1;
diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h
index 53aa05d..3af7c3d 100644
--- a/libinstaller/syslxint.h
+++ b/libinstaller/syslxint.h
@@ -105,6 +105,56 @@ static inline void set_64(uint64_t *p, uint64_t v)
 #endif
 }
 
+/*
+ * Special handling for the MS-DOS derivative: syslinux_ldlinux
+ * is a "far" object...
+ */
+#ifdef __MSDOS__
+
+extern uint16_t ldlinux_seg;	/* Defined in dos/syslinux.c */
+
+static inline __attribute__ ((const))
+uint16_t ds(void)
+{
+    uint16_t v;
+    asm("movw %%ds,%0":"=rm"(v));
+    return v;
+}
+
+static inline void *set_fs(const void *p)
+{
+    uint16_t seg;
+
+    seg = ldlinux_seg + ((size_t) p >> 4);
+    asm volatile ("movw %0,%%fs"::"rm" (seg));
+    return (void *)((size_t) p & 0xf);
+}
+
+uint8_t get_8_sl(const uint8_t * p);
+uint16_t get_16_sl(const uint16_t * p);
+uint32_t get_32_sl(const uint32_t * p);
+uint64_t get_64_sl(const uint64_t * p);
+void set_8_sl(uint8_t * p, uint8_t v);
+void set_16_sl(uint16_t * p, uint16_t v);
+void set_32_sl(uint32_t * p, uint32_t v);
+void set_64_sl(uint64_t * p, uint64_t v);
+void memcpy_to_sl(void *dst, const void *src, size_t len);
+
+#else
+
+/* Sane system ... */
+#define get_8_sl(x)    		get_8(x)
+#define get_16_sl(x)   		get_16(x)
+#define get_32_sl(x)   		get_32(x)
+#define get_64_sl(x)   		get_64(x)
+#define set_8_sl(x,y)  		set_8(x,y)
+#define set_16_sl(x,y) 		set_16(x,y)
+#define set_32_sl(x,y) 		set_32(x,y)
+#define set_64_sl(x,y) 		set_64(x,y)
+#define memcpy_to_sl(d,s,l)	memcpy(d,s,l)
+
+#endif
+
 #define LDLINUX_MAGIC	0x3eb202fe
 
 /* Patch area for disk-based installers */
@@ -116,13 +166,21 @@ struct patch_area {
     uint32_t dwords;
     uint32_t checksum;
     uint16_t maxtransfer;
-    uint16_t advptroffset;
-    uint16_t diroffset;
-    uint16_t dirlen;
-    uint16_t subvoloffset;
-    uint16_t subvollen;
-    uint16_t secptroffset;
-    uint16_t secptrcnt;
+    uint16_t epaoffset;		/* Pointer to the extended patch area */
+};
+
+struct ext_patch_area {
+    uint16_t advptroffset;	/* ADV pointers */
+    uint16_t diroffset;		/* Current directory field */
+    uint16_t dirlen;		/* Length of current directory field */
+    uint16_t subvoloffset;	/* Subvolume field */
+    uint16_t subvollen;		/* Length of subvolume field */
+    uint16_t secptroffset;	/* Sector extent pointers */
+    uint16_t secptrcnt;		/* Number of sector extent pointers */
+
+    uint16_t sect1ptr0;		/* Boot sector offset of sector 1 ptr LSW */
+    uint16_t sect1ptr1;		/* Boot sector offset of sector 1 ptr MSW */
+    uint16_t raidpatch;		/* Boot sector RAID mode patch pointer */
 };
 
 /* Sector extent */
@@ -156,7 +214,7 @@ struct boot_sector {
 	    uint32_t VolumeID;
 	    char VolumeLabel[11];
 	    char FileSysType[8];
-	    uint8_t Code[440];
+	    uint8_t Code[448];
 	} __attribute__ ((packed)) bs16;
 	struct {
 	    uint32_t FATSz32;
@@ -172,11 +230,10 @@ struct boot_sector {
 	    uint32_t VolumeID;
 	    char VolumeLabel[11];
 	    char FileSysType[8];
-	    uint8_t Code[412];
+	    uint8_t Code[420];
 	} __attribute__ ((packed)) bs32;
     } __attribute__ ((packed));
 
-    uint64_t NextSector;	/* Pointer to the first unused sector */
     uint16_t bsSignature;
 } __attribute__ ((packed));
 
diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c
index def4aab..6f5adca 100644
--- a/libinstaller/syslxmod.c
+++ b/libinstaller/syslxmod.c
@@ -129,115 +129,6 @@ const char *syslinux_check_bootsect(const void *bs)
 }
 
 /*
- * Special handling for the MS-DOS derivative: syslinux_ldlinux
- * is a "far" object...
- */
-#ifdef __MSDOS__
-
-#define __noinline __attribute__((noinline))
-
-extern uint16_t ldlinux_seg;	/* Defined in dos/syslinux.c */
-
-static inline __attribute__ ((const))
-uint16_t ds(void)
-{
-    uint16_t v;
-asm("movw %%ds,%0":"=rm"(v));
-    return v;
-}
-
-static inline void *set_fs(const void *p)
-{
-    uint16_t seg;
-
-    seg = ldlinux_seg + ((size_t) p >> 4);
-    asm volatile ("movw %0,%%fs"::"rm" (seg));
-    return (void *)((size_t) p & 0xf);
-}
-
-#if 0				/* unused */
-static __noinline uint8_t get_8_sl(const uint8_t * p)
-{
-    uint8_t v;
-
-    p = set_fs(p);
-    asm volatile("movb %%fs:%1,%0":"=q" (v):"m"(*p));
-    return v;
-}
-#endif
-
-static __noinline uint16_t get_16_sl(const uint16_t * p)
-{
-    uint16_t v;
-
-    p = set_fs(p);
-    asm volatile("movw %%fs:%1,%0":"=r" (v):"m"(*p));
-    return v;
-}
-
-static __noinline uint32_t get_32_sl(const uint32_t * p)
-{
-    uint32_t v;
-
-    p = set_fs(p);
-    asm volatile("movl %%fs:%1,%0":"=r" (v):"m"(*p));
-    return v;
-}
-
-#if 0				/* unused */
-static __noinline uint64_t get_64_sl(const uint64_t * p)
-{
-    uint32_t v0, v1;
-    const uint32_t *pp = (const uint32_t *)set_fs(p);
-
-    asm volatile("movl %%fs:%1,%0" : "=r" (v0) : "m" (pp[0]));
-    asm volatile("movl %%fs:%1,%0" : "=r" (v1) : "m" (pp[1]));
-    return v0 + ((uint64_t)v1 << 32);
-}
-#endif
-
-#if 0				/* unused */
-static __noinline void set_8_sl(uint8_t * p, uint8_t v)
-{
-    p = set_fs(p);
-    asm volatile("movb %1,%%fs:%0":"=m" (*p):"qi"(v));
-}
-#endif
-
-static __noinline void set_16_sl(uint16_t * p, uint16_t v)
-{
-    p = set_fs(p);
-    asm volatile("movw %1,%%fs:%0":"=m" (*p):"ri"(v));
-}
-
-static __noinline void set_32_sl(uint32_t * p, uint32_t v)
-{
-    p = set_fs(p);
-    asm volatile("movl %1,%%fs:%0":"=m" (*p):"ri"(v));
-}
-
-static __noinline void set_64_sl(uint64_t * p, uint64_t v)
-{
-    uint32_t *pp = (uint32_t *)set_fs(p);
-    asm volatile("movl %1,%%fs:%0" : "=m" (pp[0]) : "ri"((uint32_t)v));
-    asm volatile("movl %1,%%fs:%0" : "=m" (pp[1]) : "ri"((uint32_t)(v >> 32)));
-}
-
-#else
-
-/* Sane system ... */
-#define get_8_sl(x)    get_8(x)
-#define get_16_sl(x)   get_16(x)
-#define get_32_sl(x)   get_32(x)
-#define get_64_sl(x)   get_64(x)
-#define set_8_sl(x,y)  set_8(x,y)
-#define set_16_sl(x,y) set_16(x,y)
-#define set_32_sl(x,y) set_32(x,y)
-#define set_64_sl(x,y) set_64(x,y)
-
-#endif
-
-/*
  * Generate sector extents
  */
 static void generate_extents(struct syslinux_extent *ex, int nptrs,
@@ -285,6 +176,14 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs,
 }
 
 /*
+ * Form a pointer based on a 16-bit patcharea/epa field
+ */
+static inline void *ptr(void *img, uint16_t *offset_p)
+{
+    return (char *)img + get_16_sl(offset_p);
+}
+
+/*
  * This patches the boot sector and the beginning of ldlinux.sys
  * based on an ldlinux.sys sector map passed in.  Typically this is
  * handled by writing ldlinux.sys, mapping it, and then overwrite it
@@ -301,33 +200,35 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
 		   int stupid, int raid_mode, const char *subdir)
 {
     struct patch_area *patcharea;
+    struct ext_patch_area *epa;
     struct syslinux_extent *ex;
     uint32_t *wp;
     int nsect = ((boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT) + 2;
     uint32_t csum;
     int i, dw, nptrs;
     struct boot_sector *sbs = (struct boot_sector *)boot_sector;
-    size_t diroffset, dirlen;
-    int secptroffset;
     uint64_t *advptrs;
 
     if (nsectors < nsect)
 	return -1;		/* The actual file is too small for content */
 
-    /* Handle RAID mode, write proper bsSignature */
-    i = get_16(&sbs->bsSignature);
-    if (raid_mode)
-	set_16((uint16_t *) ((char *)sbs + i), 0x18CD);	/* INT 18h */
-    set_16(&sbs->bsSignature, 0xAA55);
-
-    /* First sector need pointer in boot sector */
-    set_64(&sbs->NextSector, *sectp++);
-
     /* Search for LDLINUX_MAGIC to find the patch area */
     for (wp = (uint32_t *)boot_image; get_32_sl(wp) != LDLINUX_MAGIC;
 	 wp++)
 	;
     patcharea = (struct patch_area *)wp;
+    epa = ptr(boot_image, &patcharea->epaoffset);
+
+    /* First sector need pointer in boot sector */
+    set_32(ptr(sbs, &epa->sect1ptr0), sectp[0]);
+    set_32(ptr(sbs, &epa->sect1ptr1), sectp[0] >> 32);
+    sectp++;
+
+    /* Handle RAID mode */
+    if (raid_mode) {
+	/* Patch in INT 18h = CD 18 */
+	set_16(ptr(sbs, &epa->raidpatch), 0x18CD);
+    }
 
     /* Set up the totals */
     dw = boot_image_len >> 2;	/* COMPLETE dwords, excluding ADV */
@@ -338,13 +239,12 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
     /* Handle Stupid mode */
     if (stupid) {
 	/* Access only one sector at a time */
-	set_16(&patcharea->maxtransfer, 1);
+	set_16_sl(&patcharea->maxtransfer, 1);
     }
 
     /* Set the sector extents */
-    secptroffset = get_16_sl(&patcharea->secptroffset);
-    ex = (struct syslinux_extent *) ((char *)boot_image + secptroffset);
-    nptrs = get_16_sl(&patcharea->secptrcnt);
+    ex = ptr(boot_image, &epa->secptroffset);
+    nptrs = get_16_sl(&epa->secptrcnt);
 
     if (nsect > nptrs) {
 	/* Not necessarily an error in this case, but a general problem */
@@ -356,20 +256,18 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
     generate_extents(ex, nptrs, sectp, nsect-1-2);
 
     /* ADV pointers */
-    advptrs = (uint64_t *)((char *)boot_image +
-			   get_16_sl(&patcharea->advptroffset));
+    advptrs = ptr(boot_image, &epa->advptroffset);
     set_64_sl(&advptrs[0], sectp[nsect-1-2]);
     set_64_sl(&advptrs[1], sectp[nsect-1-1]);
 
     /* Poke in the base directory path */
     if (subdir) {
-	diroffset = get_16(&patcharea->diroffset);
-	dirlen = get_16(&patcharea->dirlen);
-	if (dirlen <= strlen(subdir)) {
+	int sublen = strlen(subdir) + 1;
+	if (get_16_sl(&epa->dirlen) < sublen) {
 	    fprintf(stderr, "Subdirectory path too long... aborting install!\n");
 	    exit(1);
 	}
-	memcpy((char *)boot_image + diroffset, subdir, strlen(subdir) + 1);
+	memcpy_to_sl(ptr(boot_image, &epa->diroffset), subdir, sublen);
     }
 
     /* Now produce a checksum */
@@ -381,5 +279,9 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
 
     set_32_sl(&patcharea->checksum, csum);
 
+    /*
+     * Assume all bytes modified.  This can be optimized at the expense
+     * of keeping track of what the highest modified address ever was.
+     */
     return dw << 2;
 }



More information about the Syslinux-commits mailing list