diff options
-rw-r--r-- | core/diskstart.inc | 36 | ||||
-rw-r--r-- | dos/Makefile | 2 | ||||
-rw-r--r-- | dos/getsetsl.c | 100 | ||||
-rw-r--r-- | extlinux/main.c | 127 | ||||
-rw-r--r-- | libinstaller/syslxint.h | 77 | ||||
-rw-r--r-- | libinstaller/syslxmod.c | 162 |
6 files changed, 294 insertions, 210 deletions
diff --git a/core/diskstart.inc b/core/diskstart.inc index d858c35d..c21c9e27 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 fbaca6bd..73925711 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 00000000..a48f3df2 --- /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 6ce3b605..cf9840dd 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 53aa05dc..3af7c3d7 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 def4aaba..6f5adca5 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; } |