diff options
Diffstat (limited to 'libinstaller')
-rwxr-xr-x | libinstaller/bin2c.pl | 4 | ||||
-rw-r--r-- | libinstaller/syslinux.h | 22 | ||||
-rw-r--r-- | libinstaller/syslxint.h | 36 | ||||
-rw-r--r-- | libinstaller/syslxmod.c | 120 |
4 files changed, 140 insertions, 42 deletions
diff --git a/libinstaller/bin2c.pl b/libinstaller/bin2c.pl index 5a60ca9e..07c11ddb 100755 --- a/libinstaller/bin2c.pl +++ b/libinstaller/bin2c.pl @@ -69,10 +69,10 @@ if ($align != 0) { } } -printf "\n};\n\nunsigned int %s_len = %u;\n", $table_name, $total_len; +printf "\n};\n\nconst unsigned int %s_len = %u;\n", $table_name, $total_len; @st = stat STDIN; -printf "\nint %s_mtime = %d;\n", $table_name, $st[9]; +printf "\nconst int %s_mtime = %d;\n", $table_name, $st[9]; exit 0; diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index efffb7c0..e0554255 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -17,17 +17,21 @@ #include "advconst.h" /* The standard boot sector and ldlinux image */ -extern unsigned char syslinux_bootsect[]; -extern unsigned int syslinux_bootsect_len; -extern int syslinux_bootsect_mtime; +extern unsigned char syslinux_bootsect[]; +extern const unsigned int syslinux_bootsect_len; +extern const int syslinux_bootsect_mtime; -extern unsigned char syslinux_ldlinux[]; -extern unsigned int syslinux_ldlinux_len; -extern int syslinux_ldlinux_mtime; +extern unsigned char syslinux_ldlinux[]; +extern const unsigned int syslinux_ldlinux_len; +extern const int syslinux_ldlinux_mtime; -extern unsigned char syslinux_mbr[]; -extern unsigned int syslinux_mbr_len; -extern int syslinux_mbr_mtime; +extern unsigned char syslinux_mbr[]; +extern const unsigned int syslinux_mbr_len; +extern const int syslinux_mbr_mtime; + +/* Sector size assumptions... */ +#define SECTOR_BITS 9 +#define SECTOR_SIZE (1 << SECTOR_BITS) /* This takes a boot sector and merges in the syslinux fields */ void syslinux_make_bootsect(void *); diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h index 3f50e32c..fc3932b2 100644 --- a/libinstaller/syslxint.h +++ b/libinstaller/syslxint.h @@ -20,16 +20,17 @@ */ static inline uint8_t get_8(const uint8_t *p) { - return *(const uint8_t *)p; + return *p; } static inline uint16_t get_16(const uint16_t *p) { #if defined(__i386__) || defined(__x86_64__) /* Littleendian and unaligned-capable */ - return *(const uint16_t *)p; + return *p; #else - return (uint16_t)p[0] + ((uint16_t)p[1] << 8); + const uint8_t *pp = (const uint8_t *)p; + return (uint16_t)pp[0] + ((uint16_t)pp[1] << 8); #endif } @@ -37,21 +38,28 @@ static inline uint32_t get_32(const uint32_t *p) { #if defined(__i386__) || defined(__x86_64__) /* Littleendian and unaligned-capable */ - return *(const uint32_t *)p; + return *p; #else - return (uint32_t)p[0] + ((uint32_t)p[1] << 8) + - ((uint32_t)p[2] << 16) + ((uint32_t)p[3] << 24); + const uint8_t *pp = (const uint8_t *)p; + return (uint32_t)pp[0] + ((uint32_t)pp[1] << 8) + + ((uint32_t)pp[2] << 16) + ((uint32_t)pp[3] << 24); #endif } +static inline void set_8(uint8_t *p, uint8_t v) +{ + *p = v; +} + static inline void set_16(uint16_t *p, uint16_t v) { #if defined(__i386__) || defined(__x86_64__) /* Littleendian and unaligned-capable */ *(uint16_t *)p = v; #else - p[0] = (v & 0xff); - p[1] = ((v >> 8) & 0xff); + uint8_t *pp = (uint8_t *)p; + pp[0] = (v & 0xff); + pp[1] = ((v >> 8) & 0xff); #endif } @@ -61,16 +69,14 @@ static inline void set_32(uint32_t *p, uint32_t v) /* Littleendian and unaligned-capable */ *(uint32_t *)p = v; #else - p[0] = (v & 0xff); - p[1] = ((v >> 8) & 0xff); - p[2] = ((v >> 16) & 0xff); - p[3] = ((v >> 24) & 0xff); + uint8_t *pp = (uint8_t *)p; + pp[0] = (v & 0xff); + pp[1] = ((v >> 8) & 0xff); + pp[2] = ((v >> 16) & 0xff); + pp[3] = ((v >> 24) & 0xff); #endif } -#define SECTOR_SHIFT 9 /* 512-byte sectors */ -#define SECTOR_SIZE (1 << SECTOR_SHIFT) - #define LDLINUX_MAGIC 0x3eb202fe /* Patch area for disk-based installers */ diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index 1766de2b..78e226c4 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -121,6 +121,88 @@ const char *syslinux_check_bootsect(const void *bs) } /* + * Special handling for the MS-DOS derivative: syslinux_ldlinux + * is a "far" object... + */ +#ifdef __MSDOS__ + +extern const char __payload_sseg[]; /* Symbol from linker */ + +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 = ds() + (size_t)__payload_sseg; + seg += (size_t)p >> 4; + asm volatile("movw %0,%%fs" : : "rm" (seg)); + return (void *)((size_t)p & 0xf); +} + +static inline 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; +} + +static inline 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 inline 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; +} + +static inline void set_8_sl(uint8_t *p, uint8_t v) +{ + p = set_fs(p); + asm volatile("movb %1,%%fs:%0" : "=m" (*p) : "qi" (v)); +} + +static inline 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 inline void set_32_sl(uint32_t *p, uint32_t v) +{ + p = set_fs(p); + asm volatile("movl %1,%%fs:%0" : "=m" (*p) : "ri" (v)); +} + +#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 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) + +#endif + +/* * 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 @@ -128,7 +210,8 @@ const char *syslinux_check_bootsect(const void *bs) * an OS which does block reallocation, then overwrite it with * direct access since the location is known. * - * Return 0 if successful, otherwise -1. + * Returns the number of modified bytes in ldlinux.sys if successful, + * otherwise -1. */ int syslinux_patch(const uint32_t *sectors, int nsectors, int stupid, int raid_mode) @@ -137,7 +220,7 @@ int syslinux_patch(const uint32_t *sectors, int nsectors, uint32_t *wp; int nsect = (syslinux_ldlinux_len+511) >> 9; uint32_t csum; - int i, dw, nptrs; + int i, dw, nptrs, rv; if ( nsectors < nsect ) return -1; @@ -157,33 +240,38 @@ int syslinux_patch(const uint32_t *sectors, int nsectors, set_32(&sbs->NextSector, *sectors++); /* Search for LDLINUX_MAGIC to find the patch area */ - for (wp = (uint32_t *)syslinux_ldlinux; get_32(wp) != LDLINUX_MAGIC; wp++) + for (wp = (uint32_t *)syslinux_ldlinux; get_32_sl(wp) != LDLINUX_MAGIC; wp++) ; patcharea = (struct patch_area *)wp; /* Set up the totals */ dw = syslinux_ldlinux_len >> 2; /* COMPLETE dwords, excluding ADV */ - set_16(&patcharea->data_sectors, nsect); /* Not including ADVs */ - set_16(&patcharea->adv_sectors, 0); /* ADVs not supported yet */ - set_32(&patcharea->dwords, dw); - set_32(&patcharea->currentdir, 0); + set_16_sl(&patcharea->data_sectors, nsect); /* Not including ADVs */ + set_16_sl(&patcharea->adv_sectors, 0); /* ADVs not supported yet */ + set_32_sl(&patcharea->dwords, dw); + set_32_sl(&patcharea->currentdir, 0); /* Set the sector pointers */ - wp = (uint32_t *)((char *)syslinux_ldlinux+get_16(&patcharea->secptroffset)); - nptrs = get_16(&patcharea->secptrcnt); + wp = (uint32_t *)((char *)syslinux_ldlinux+get_16_sl(&patcharea->secptroffset)); + nptrs = get_16_sl(&patcharea->secptrcnt); + + while (nsect--) { + set_32_sl(wp++, *sectors++); + nptrs--; + } + while (nptrs--) + set_32_sl(wp++, 0); - memset(wp, 0, nptrs*4); - while ( nsect-- ) - set_32(wp++, *sectors++); + rv = (char *)wp - (char *)syslinux_ldlinux; /* Now produce a checksum */ - set_32(&patcharea->checksum, 0); + set_32_sl(&patcharea->checksum, 0); csum = LDLINUX_MAGIC; for (i = 0, wp = (uint32_t *)syslinux_ldlinux; 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); - return 0; + return rv; } |