This set of patches add some support for sector size >512. Currently it fixes extlinux, MBR for GPT and ext partitions. Other code is unaffected. This set of patches has been tested on a read Dell machine running a beta firmware.
after read_sector %edx:%eax are unused or incremented so increment always at end gaining 3 bytes Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- mbr/gptmbr.S | 19 ++++++++++--------- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S index ae0549f..ef2235d 100644 --- a/mbr/gptmbr.S +++ b/mbr/gptmbr.S @@ -142,7 +142,6 @@ next: pushw %bx get_ptab: call read_sector - call inc64 loopw get_ptab /* Find the boot partition */ @@ -240,16 +239,9 @@ saturate_stosl: ret /* - * Increment %edx:%eax - */ -inc64: - addl $1,%eax - adcl $0,%edx - ret - -/* * read_sector: read a single sector pointed to by %edx:%eax to * %es:%bx. CF is set on error. All registers saved. + * %edx:%eax and %es:%bx are incremented to read next sector */ read_sector: pushal @@ -282,6 +274,15 @@ read_common: popal jc disk_error addb $2, %bh /* bx += 512: point to the next buffer */ + + /* fall through and increment sector number */ + +/* + * Increment %edx:%eax + */ +inc64: + addl $1,%eax + adcl $0,%edx ret disk_error: -- 1.7.5.4
Frediano Ziglio
2012-Sep-10 08:43 UTC
[syslinux] [PATCH 2/8] Save some bytes adding a function to set bx before read_sector
Mostly of the time bx was set as phdr before calling read_sector so add a specific function to set %bx and call read_sector gaining 2 bytes Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- mbr/gptmbr.S | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S index ef2235d..f73b472 100644 --- a/mbr/gptmbr.S +++ b/mbr/gptmbr.S @@ -118,9 +118,7 @@ next: xorl %eax,%eax cltd incw %ax /* %edx:%eax = 1 */ - movw $phdr, %bx - pushw %bx /* -8(%bp) phdr == bootsect */ - call read_sector + call read_sector_phdr /* Number of partition sectors */ /* We assume the partition table is 32K or less, and that @@ -215,8 +213,7 @@ found_part: boot: movl (32+20)(%si),%eax movl (36+20)(%si),%edx - popw %bx - call read_sector + call read_sector_phdr cmpw $0xaa55, -2(%bx) jne missing_os /* Not a valid boot sector */ movw %bp, %sp /* driveno == bootsec-6 */ @@ -238,6 +235,11 @@ saturate_stosl: 1: stosl ret +read_sector_phdr: + movw $phdr, %bx + + /* fall through and read sector */ + /* * read_sector: read a single sector pointed to by %edx:%eax to * %es:%bx. CF is set on error. All registers saved. -- 1.7.5.4
Frediano Ziglio
2012-Sep-10 08:43 UTC
[syslinux] [PATCH 3/8] Reduce size reducing a message
Easy way to reduce code but actually I found the message is readable at the same way as previous. Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- mbr/gptmbr.S | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S index f73b472..b0c11b9 100644 --- a/mbr/gptmbr.S +++ b/mbr/gptmbr.S @@ -289,7 +289,7 @@ inc64: disk_error: call error - .ascii "Disk error on boot\r\n" + .ascii "Disk error\r\n" /* * Print error messages. This is invoked with "call", with the -- 1.7.5.4
If EBIOS is detected for this drive it tries to read sector size and use it. If error or no EBIOS 512 is assumed. Buffer to read sector size is always allocated into the stack. CHS informations are not readed as not needed and save space not restoring %dl for drive number. Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- mbr/gptmbr.S | 41 +++++++++++++++++++++++++++-------------- 1 files changed, 27 insertions(+), 14 deletions(-) diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S index b0c11b9..88d2809 100644 --- a/mbr/gptmbr.S +++ b/mbr/gptmbr.S @@ -77,6 +77,12 @@ next: ADJUST_DRIVE pushw %dx /* 0(%bp) = %dl -> drive number */ + movw %sp, %bp /* %bp -> frame pointer: LEAVE UNCHANGED */ + + /* prepare to read sector size */ + sub $0x1c, %sp /* -28(%bp) == %sp */ + pushw $0x1e /* -30(%bp) == %sp */ + movw $0x200, -6(%bp) /* -6(%bp) sector size */ /* Check to see if we have EBIOS */ pushw %dx /* drive number */ @@ -86,6 +92,8 @@ next: xorb %dh, %dh stc int $0x13 + popw %dx /* restore drive */ + movb $0x08, %ah /* get CHS geometry */ jc 1f cmpw $0xaa55, %bx jne 1f @@ -97,22 +105,28 @@ next: movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \ (read_sector_cbios) -1: - popw %dx + /* + * read sector size. + * Should not fail but if it does I assume that at least + * previous 512 value is not overridden + */ + movb $0x48, %ah + movw %sp, %si +1: /* Get (C)HS geometry */ - movb $0x08, %ah int $0x13 + + /* here we computer CHS values or just do some dummy computation for EBIOS */ andw $0x3f, %cx /* Sector count */ - movw %sp, %bp /* %bp -> frame pointer: LEAVE UNCHANGED */ - pushw %cx /* -2(%bp) Save sectors on the stack */ + pushw %cx /* -32(%bp) Save sectors on the stack */ movzbw %dh, %ax /* dh = max head */ incw %ax /* From 0-based max to count */ mulw %cx /* Heads*sectors -> sectors per cylinder */ /* Save sectors/cylinder on the stack */ - pushw %dx /* -4(%bp) High word */ - pushw %ax /* -6(%bp) Low word */ + pushw %dx /* -34(%bp) High word */ + pushw %ax /* -36(%bp) Low word */ /* Load partition table header */ xorl %eax,%eax @@ -121,15 +135,14 @@ next: call read_sector_phdr /* Number of partition sectors */ - /* We assume the partition table is 32K or less, and that - the sector size is 512. */ + /* We assume the partition table is 32K or less */ /* Note: phdr == 6(%bp) */ movw (80+6)(%bp),%cx /* NumberOfPartitionEntries */ movw (84+6)(%bp),%ax /* SizeOfPartitionEntry */ pushw %ax pushw %cx mulw %cx - shrw $9,%ax + divw -6(%bp) /* %dx == 0 here */ xchgw %ax,%cx incw %cx @@ -214,7 +227,7 @@ boot: movl (32+20)(%si),%eax movl (36+20)(%si),%edx call read_sector_phdr - cmpw $0xaa55, -2(%bx) + cmpw $0xaa55, (0x7c00+0x1fe) jne missing_os /* Not a valid boot sector */ movw %bp, %sp /* driveno == bootsec-6 */ popw %dx /* dl -> drive number */ @@ -258,12 +271,12 @@ read_sector: /* This chunk is skipped if we have ebios */ /* Do not clobber %es:%bx or %edx:%eax before this chunk! */ read_sector_cbios: - divl -6(%bp) /* secpercyl */ + divl -36(%bp) /* secpercyl */ shlb $6, %ah movb %ah, %cl movb %al, %ch xchgw %dx, %ax - divb -2(%bp) /* sectors */ + divb -32(%bp) /* sectors */ movb %al, %dh orb %ah, %cl incw %cx /* Sectors are 1-based */ @@ -275,7 +288,7 @@ read_common: leaw 16(%si), %sp /* Drop DAPA */ popal jc disk_error - addb $2, %bh /* bx += 512: point to the next buffer */ + addb -5(%bp), %bh /* bx += sector size: point to the next buffer */ /* fall through and increment sector number */ -- 1.7.5.4
Limit some function visibility in extlinux. Also reamore an unused NADV define. Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- extlinux/main.c | 8 ++++---- libinstaller/syslxmod.c | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/extlinux/main.c b/extlinux/main.c index 73f3fbe..f0d8e11 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -76,7 +76,7 @@ static char subvol[BTRFS_SUBVOL_MAX]; /* * Get the size of a block device */ -uint64_t get_size(int devfd) +static uint64_t get_size(int devfd) { uint64_t bytes; uint32_t sects; @@ -210,7 +210,7 @@ ok: * * Returns the number of modified bytes in the boot file. */ -int patch_file_and_bootblock(int fd, const char *dir, int devfd) +static int patch_file_and_bootblock(int fd, const char *dir, int devfd) { struct stat dirst, xdst; struct hd_geometry geo; @@ -746,7 +746,7 @@ static char * get_default_subvol(char * rootdir, char * subvol) return subvol; } -int install_file(const char *path, int devfd, struct stat *rst) +static int install_file(const char *path, int devfd, struct stat *rst) { if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) return ext2_fat_install_file(path, devfd, rst); @@ -1174,7 +1174,7 @@ static int ext_write_adv(const char *path, const char *cfg, int devfd) return write_adv(path, cfg); } -int install_loader(const char *path, int update_only) +static int install_loader(const char *path, int update_only) { struct stat st, fst; int devfd, rv; diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index 2436845..c706f2c 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -96,8 +96,6 @@ static inline void *ptr(void *img, uint16_t *offset_p) * Returns the number of modified bytes in ldlinux.sys if successful, * otherwise -1. */ -#define NADV 2 - int syslinux_patch(const sector_t *sectp, int nsectors, int stupid, int raid_mode, const char *subdir, const char *subvol) -- 1.7.5.4
Frediano Ziglio
2012-Sep-10 08:43 UTC
[syslinux] [PATCH 6/8] Make sector size dynamic in extlinux
Instead of using SECTOR_SIZE as a constant everywhere pass the sector size to syslinux_patch. This patch compute read sector size only in extlinux. Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- dos/syslinux.c | 2 +- extlinux/main.c | 36 +++++++++++++++++++++++++----------- libinstaller/syslinux.h | 3 ++- libinstaller/syslxcom.c | 30 +++++++++++++++--------------- libinstaller/syslxcom.h | 2 +- libinstaller/syslxmod.c | 14 ++++++++------ linux/syslinux.c | 4 ++-- mtools/syslinux.c | 2 +- win/syslinux.c | 3 ++- 9 files changed, 57 insertions(+), 39 deletions(-) diff --git a/dos/syslinux.c b/dos/syslinux.c index fa4bf38..6cd36d0 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -723,7 +723,7 @@ int main(int argc, char *argv[]) /* * Patch ldlinux.sys and the boot sector */ - i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL); + i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, SECTOR_SIZE); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* diff --git a/extlinux/main.c b/extlinux/main.c index f0d8e11..e40b4d7 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -95,6 +95,18 @@ static uint64_t get_size(int devfd) } /* + * Get sector size + */ +static unsigned get_sector_size(int devfd) +{ + int size; + + if (!ioctl(devfd, BLKSSZGET, &size)) + return size; + return SECTOR_SIZE; +} + +/* * Get device geometry and partition offset */ struct geometry_table { @@ -145,7 +157,7 @@ static const struct geometry_table standard_geometries[] = { {0, {0, 0, 0, 0}} }; -int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) +static int get_geometry(int devfd, uint64_t totalbytes, unsigned sector_size, struct hd_geometry *geo) { struct floppy_struct fd_str; struct loop_info li; @@ -179,7 +191,7 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) geo->heads = opt.heads ? : 64; geo->sectors = opt.sectors ? : 32; - geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT); + geo->cylinders = totalbytes / (geo->heads * geo->sectors * sector_size); geo->start = 0; if (!opt.sectors && !opt.heads) { @@ -193,11 +205,11 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) ok: /* If this is a loopback device, try to set the start */ if (!ioctl(devfd, LOOP_GET_STATUS64, &li64)) - geo->start = li64.lo_offset >> SECTOR_SHIFT; + geo->start = li64.lo_offset / sector_size; else if (!ioctl(devfd, LOOP_GET_STATUS, &li)) - geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT; + geo->start = (unsigned int)li.lo_offset / sector_size; else if (!sysfs_get_offset(devfd, &geo->start)) { - /* OK */ + geo->start /= (sector_size / SECTOR_SIZE); } return rv; @@ -220,6 +232,7 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) struct fat_boot_sector *sbs; char *dirpath, *subpath, *xdirpath; int rv; + unsigned sector_size; dirpath = realpath(dir, NULL); if (!dirpath || stat(dir, &dirst)) { @@ -262,7 +275,8 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) dprintf("subpath = %s\n", subpath); totalbytes = get_size(devfd); - get_geometry(devfd, totalbytes, &geo); + sector_size = get_sector_size(devfd); + get_geometry(devfd, totalbytes, sector_size, &geo); if (opt.heads) geo.heads = opt.heads; @@ -276,7 +290,7 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) sbs = (struct fat_boot_sector *)syslinux_bootsect; - totalsectors = totalbytes >> SECTOR_SHIFT; + totalsectors = totalbytes / sector_size; if (totalsectors >= 65536) { set_16(&sbs->bsSectors, 0); } else { @@ -284,7 +298,7 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) } set_32(&sbs->bsHugeSectors, totalsectors); - set_16(&sbs->bsBytesPerSec, SECTOR_SIZE); + set_16(&sbs->bsBytesPerSec, sector_size); set_16(&sbs->bsSecPerTrack, geo.sectors); set_16(&sbs->bsHeads, geo.heads); set_32(&sbs->bsHiddenSecs, geo.start); @@ -292,11 +306,11 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) /* Construct the boot file map */ dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino); - nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + nsect = (boot_image_len + sector_size - 1) / sector_size; nsect += 2; /* Two sectors for the ADV */ sectp = alloca(sizeof(sector_t) * nsect); if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) { - if (sectmap(fd, sectp, nsect)) { + if (sectmap(fd, sectp, nsect, sector_size)) { perror("bmap"); exit(1); } @@ -312,7 +326,7 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) /* Create the modified image in memory */ rv = syslinux_patch(sectp, nsect, opt.stupid_mode, - opt.raid_mode, subpath, subvol); + opt.raid_mode, subpath, subvol, sector_size); free(dirpath); return rv; diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index 8b86f88..75ed451 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -49,6 +49,7 @@ const char *syslinux_check_bootsect(const void *bs, int *fs_type); typedef uint64_t sector_t; int syslinux_patch(const sector_t *sectors, int nsectors, int stupid, int raid_mode, - const char *subdir, const char *subvol); + const char *subdir, const char *subvol, + unsigned sector_size); #endif diff --git a/libinstaller/syslxcom.c b/libinstaller/syslxcom.c index 57f13cd..95a7110 100644 --- a/libinstaller/syslxcom.c +++ b/libinstaller/syslxcom.c @@ -45,8 +45,6 @@ int fs_type; # define dprintf(...) ((void)0) #endif -#define SECTOR_SHIFT 9 - static void die(const char *msg) { fputs(msg, stderr); @@ -176,7 +174,7 @@ void set_attributes(int fd) } /* New FIEMAP based mapping */ -static int sectmap_fie(int fd, sector_t *sectors, int nsectors) +static int sectmap_fie(int fd, sector_t *sectors, int nsectors, unsigned sector_size) { struct fiemap *fm; struct fiemap_extent *fe; @@ -193,7 +191,7 @@ static int sectmap_fie(int fd, sector_t *sectors, int nsectors) memset(fm, 0, sizeof *fm); - maplen = (uint64_t)nsectors << SECTOR_SHIFT; + maplen = (uint64_t)nsectors * sector_size; if (maplen > (uint64_t)st.st_size) maplen = st.st_size; @@ -217,12 +215,12 @@ static int sectmap_fie(int fd, sector_t *sectors, int nsectors) for (i = 0; i < fm->fm_mapped_extents; i++) { if (fe->fe_flags & FIEMAP_EXTENT_LAST) { /* If this is the *final* extent, pad the length */ - fe->fe_length = (fe->fe_length + SECTOR_SIZE - 1) - & ~(SECTOR_SIZE - 1); + fe->fe_length = (fe->fe_length + sector_size - 1) + & ~(sector_size - 1); } if ((fe->fe_logical | fe->fe_physical| fe->fe_length) & - (SECTOR_SIZE - 1)) + (sector_size - 1)) return -1; if (fe->fe_flags & (FIEMAP_EXTENT_UNKNOWN| @@ -232,9 +230,9 @@ static int sectmap_fie(int fd, sector_t *sectors, int nsectors) FIEMAP_EXTENT_UNWRITTEN)) return -1; - secp = sectors + (fe->fe_logical >> SECTOR_SHIFT); - sec = fe->fe_physical >> SECTOR_SHIFT; - nsec = fe->fe_length >> SECTOR_SHIFT; + secp = sectors + (fe->fe_logical / sector_size); + sec = fe->fe_physical / sector_size; + nsec = fe->fe_length / sector_size; while (nsec--) { if (secp >= esec) @@ -249,7 +247,7 @@ static int sectmap_fie(int fd, sector_t *sectors, int nsectors) } /* Legacy FIBMAP based mapping */ -static int sectmap_fib(int fd, sector_t *sectors, int nsectors) +static int sectmap_fib(int fd, sector_t *sectors, int nsectors, unsigned sector_size) { unsigned int blk, nblk; unsigned int i; @@ -261,7 +259,9 @@ static int sectmap_fib(int fd, sector_t *sectors, int nsectors) return -1; /* Number of sectors per block */ - blksize >>= SECTOR_SHIFT; + blksize /= sector_size; + if (blksize == 0) + return -1; nblk = 0; while (nsectors) { @@ -283,12 +283,12 @@ static int sectmap_fib(int fd, sector_t *sectors, int nsectors) /* * Produce file map */ -int sectmap(int fd, sector_t *sectors, int nsectors) +int sectmap(int fd, sector_t *sectors, int nsectors, unsigned sector_size) { - if (!sectmap_fie(fd, sectors, nsectors)) + if (!sectmap_fie(fd, sectors, nsectors, sector_size)) return 0; - return sectmap_fib(fd, sectors, nsectors); + return sectmap_fib(fd, sectors, nsectors, sector_size); } /* diff --git a/libinstaller/syslxcom.h b/libinstaller/syslxcom.h index 8b3b461..111b634 100644 --- a/libinstaller/syslxcom.h +++ b/libinstaller/syslxcom.h @@ -8,7 +8,7 @@ ssize_t xpread(int fd, void *buf, size_t count, off_t offset); ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset); void clear_attributes(int fd); void set_attributes(int fd); -int sectmap(int fd, sector_t *sectors, int nsectors); +int sectmap(int fd, sector_t *sectors, int nsectors, unsigned sector_size); int syslinux_already_installed(int dev_fd); #endif diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index c706f2c..be101f9 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -31,7 +31,8 @@ * Generate sector extents */ static void generate_extents(struct syslinux_extent *ex, int nptrs, - const sector_t *sectp, int nsect) + const sector_t *sectp, int nsect, + unsigned sector_size) { uint32_t addr = 0x8000; /* ldlinux.sys starts loading here */ uint32_t base; @@ -47,7 +48,7 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs, sect = *sectp++; if (len) { - uint32_t xbytes = (len + 1) * SECTOR_SIZE; + uint32_t xbytes = (len + 1) * sector_size; if (sect == lba + len && xbytes < 65536 && ((addr ^ (base + xbytes - 1)) & 0xffff0000) == 0) { @@ -66,7 +67,7 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs, len = 1; next: - addr += SECTOR_SIZE; + addr += sector_size; nsect--; } @@ -98,13 +99,14 @@ static inline void *ptr(void *img, uint16_t *offset_p) */ int syslinux_patch(const sector_t *sectp, int nsectors, int stupid, int raid_mode, - const char *subdir, const char *subvol) + const char *subdir, const char *subvol, + unsigned sector_size) { 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; + int nsect = ((boot_image_len + sector_size - 1) / sector_size) + 2; uint32_t csum; int i, dw, nptrs; struct fat_boot_sector *sbs = (struct fat_boot_sector *)boot_sector; @@ -154,7 +156,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors, } /* -1 for the pointer in the boot sector, -2 for the two ADVs */ - generate_extents(ex, nptrs, sectp, nsect-1-2); + generate_extents(ex, nptrs, sectp, nsect-1-2, sector_size); /* ADV pointers */ advptrs = ptr(boot_image, &epa->advptroffset); diff --git a/linux/syslinux.c b/linux/syslinux.c index 4b13b7f..22983f9 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -444,7 +444,7 @@ int main(int argc, char *argv[]) */ ldlinux_sectors += 2; /* 2 ADV sectors */ sectors = calloc(ldlinux_sectors, sizeof *sectors); - if (sectmap(fd, sectors, ldlinux_sectors)) { + if (sectmap(fd, sectors, ldlinux_sectors, SECTOR_SIZE)) { perror("bmap"); exit(1); } @@ -463,7 +463,7 @@ umount: * Patch ldlinux.sys and the boot sector */ i = syslinux_patch(sectors, ldlinux_sectors, opt.stupid_mode, - opt.raid_mode, subdir, NULL); + opt.raid_mode, subdir, NULL, SECTOR_SIZE); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* diff --git a/mtools/syslinux.c b/mtools/syslinux.c index c65021b..6f3550f 100755 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -273,7 +273,7 @@ int main(int argc, char *argv[]) /* Patch ldlinux.sys and the boot sector */ i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, - opt.directory, NULL); + opt.directory, NULL, SECTOR_SIZE); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* Write the now-patched first sectors of ldlinux.sys */ diff --git a/win/syslinux.c b/win/syslinux.c index 669450e..cbf003f 100644 --- a/win/syslinux.c +++ b/win/syslinux.c @@ -432,7 +432,8 @@ map_done: /* * Patch ldlinux.sys and the boot sector */ - syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL); + syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, + SECTOR_SIZE); /* * Rewrite the file -- 1.7.5.4
Instead of assuming that sector size is always 512 add a function that take byte offsets instead of number of sectors and call it when needed a specific range of bytes (for instance to read partition headers). Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- core/fs/diskio.c | 80 +++++++++++++++++++++++++++++++++++++++++++-- core/fs/ext2/ext2.c | 2 +- core/fs/fat/fat.c | 2 +- core/fs/iso9660/iso9660.c | 8 ++-- core/fs/ntfs/ntfs.c | 4 +- core/include/disk.h | 2 + 6 files changed, 87 insertions(+), 11 deletions(-) diff --git a/core/fs/diskio.c b/core/fs/diskio.c index 6683816..7e58d6f 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -265,6 +265,80 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, return done; } +#define rdwr_sectors0(buf, lba, count, is_write) \ + disk->rdwr_sectors(disk, buf, lba, count, is_write) +/* + * Read a range of bytes + */ +int rdwr_bytes(struct disk *disk, void *buf, + bytes_t lba, size_t count, bool is_write) +{ + int done, res; + unsigned mask, before, len; + unsigned shift = disk->sector_shift; + + dprintf("called rdwr_bytes from %llu for %u bytes\n", (unsigned long long) lba, (unsigned) count); + + mask = disk->sector_size - 1; + + /* aligned, fix count/lba */ + if (((lba|count) & mask) == 0) { + return (rdwr_sectors0(buf, lba >> shift, count >> shift, is_write) << shift); + } + + /* do the hard work */ + done = 0; + if ((lba & mask) != 0) { + /* align start sector */ + before = lba & mask; + len = disk->sector_size - before; + if (len > count) len = count; + res = rdwr_sectors0(core_xfer_buf, lba >> shift, 1, 0); + if (!res) return done; + if (is_write) { + memcpy(core_xfer_buf + before, buf, len); + res = rdwr_sectors0(core_xfer_buf, lba >> shift, 1, 1); + if (!res) return done; + } else { + memcpy(buf, core_xfer_buf + before, len); + } + buf += len; + lba += len; + count -= len; + done += len; + } + + /* read/write full sectors */ + len = count >> shift; + if (len) { + res = rdwr_sectors0(buf, lba >> shift, len, is_write) << shift; + done += res; + len <<= shift; + if (res < len) return done; + lba += len; + count -= len; + done += len; + buf += len; + } + + /* last partial sector */ + if (count) { + len = count; + res = rdwr_sectors0(core_xfer_buf, lba >> shift, 1, 0); + if (!res) return done; + if (is_write) { + memcpy(core_xfer_buf, buf, len); + res = rdwr_sectors0(core_xfer_buf, lba >> shift, 1, 1); + if (!res) return done; + } else { + memcpy(buf, core_xfer_buf, len); + } + done += len; + } + + return done; +} + struct edd_disk_params { uint16_t len; uint16_t flags; @@ -292,9 +366,7 @@ static inline bool is_power_of_2(uint32_t x) void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) { - int sec_per_block = block_size / disk->sector_size; - - disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0); + rdwr_bytes(disk, buf, (bytes_t)block * block_size, block_size, 0); } @@ -373,6 +445,8 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, is_power_of_2(edd_params.sector_size)) sector_size = edd_params.sector_size; } + if (hard_max_transfer > (0x10000/sector_size)) + hard_max_transfer = (0x10000/sector_size); } } diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c index 3bfbb7a..8f0f2a4 100644 --- a/core/fs/ext2/ext2.c +++ b/core/fs/ext2/ext2.c @@ -276,7 +276,7 @@ static int ext2_fs_init(struct fs_info *fs) struct cache *cs; /* read the super block */ - disk->rdwr_sectors(disk, &sb, 2, 2, 0); + rdwr_bytes(disk, &sb, 2*512, 2*512, 0); /* check if it is ext2, since we also support btrfs now */ if (sb.s_magic != EXT2_SUPER_MAGIC) diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c index b08923c..3c7620e 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -731,7 +731,7 @@ static int vfat_fs_init(struct fs_info *fs) fs->sector_size = 1 << fs->sector_shift; fs->block_size = 1 << fs->block_shift; - disk->rdwr_sectors(disk, &fat, 0, 1, 0); + rdwr_bytes(disk, &fat, 0, 512, 0); /* XXX: Find better sanity checks... */ if (!fat.bxResSectors || !fat.bxFATs) diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c index 3cd3ac4..60b3b55 100644 --- a/core/fs/iso9660/iso9660.c +++ b/core/fs/iso9660/iso9660.c @@ -251,7 +251,7 @@ static int iso_fs_init(struct fs_info *fs) char pvd[2048]; /* Primary Volume Descriptor */ uint32_t pvd_lba; struct disk *disk = fs->fs_dev->disk; - int blktosec; + int blkshift; sbi = malloc(sizeof(*sbi)); if (!sbi) { @@ -268,14 +268,14 @@ static int iso_fs_init(struct fs_info *fs) fs->block_shift = 11; /* A CD-ROM block is always 2K */ fs->sector_size = 1 << fs->sector_shift; fs->block_size = 1 << fs->block_shift; - blktosec = fs->block_shift - fs->sector_shift; + blkshift = fs->block_shift; pvd_lba = iso_boot_info.pvd; if (!pvd_lba) pvd_lba = 16; /* Default if not otherwise defined */ - disk->rdwr_sectors(disk, pvd, (sector_t)pvd_lba << blktosec, - 1 << blktosec, false); + rdwr_bytes(disk, pvd, (bytes_t)pvd_lba << blkshift, + 1 << blkshift, false); memcpy(&sbi->root, pvd + ROOT_DIR_OFFSET, sizeof(sbi->root)); /* Initialize the cache */ diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c index 500d0fd..f6c8e24 100644 --- a/core/fs/ntfs/ntfs.c +++ b/core/fs/ntfs/ntfs.c @@ -1311,8 +1311,8 @@ static int ntfs_fs_init(struct fs_info *fs) dprintf("in %s()\n", __func__); - read_count = disk->rdwr_sectors(disk, &ntfs, 0, 1, 0); - if (!read_count) + read_count = rdwr_bytes(disk, &ntfs, 0, 512, 0); + if (read_count != 512) return -1; if (!ntfs_check_sb_fields(&ntfs)) diff --git a/core/include/disk.h b/core/include/disk.h index ac23e92..f0a3fa8 100644 --- a/core/include/disk.h +++ b/core/include/disk.h @@ -7,6 +7,7 @@ typedef uint64_t sector_t; typedef uint64_t block_t; +typedef uint64_t bytes_t; /* * struct disk: contains the information about a specific disk and also @@ -29,6 +30,7 @@ struct disk { extern void read_sectors(char *, sector_t, int); extern void getoneblk(struct disk *, char *, block_t, int); +extern int rdwr_bytes(struct disk *, void *, bytes_t, size_t, bool); /* diskio.c */ struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t); -- 1.7.5.4
Add offset to adv sectors. If sector size is greater than adv size you need an additional offset to specify which sector part contains the information. This patch does not support BTRFS (that will work only using 512 as sector size). Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- core/adv.inc | 76 ++++++++++++++++++++++++++++++++++++++++++++-- dos/syslinux.c | 2 +- extlinux/main.c | 24 ++++++++++----- libinstaller/syslinux.h | 2 +- libinstaller/syslxmod.c | 8 ++++- linux/syslinux.c | 2 +- mtools/syslinux.c | 2 +- win/syslinux.c | 2 +- 8 files changed, 100 insertions(+), 18 deletions(-) diff --git a/core/adv.inc b/core/adv.inc index 0b45a6c..a714800 100644 --- a/core/adv.inc +++ b/core/adv.inc @@ -356,11 +356,13 @@ adv_read_write: mov eax,[ADVSec0] mov edx,[ADVSec0+4] + mov di,[ADVOff0] mov bx,adv0 call .doone mov eax,[ADVSec1] mov edx,[ADVSec1+4] + mov di,[ADVOff1] mov bx,adv1 call .doone @@ -371,18 +373,66 @@ adv_read_write: push si jmp si + extern xfer_buf_seg .ebios: + pusha + sub sp,1ch + push 1eh + mov si,sp + mov ah,48h ; EDD get drive parameters + mov dl,[ADVDrive] + push ds + push ss + pop ds + mov word [si+18h], 512 + int 13h + mov ax, [si+18h] + pop ds + mov [ADVSsz], ax + add sp,1eh + popa + mov cx,adv_retries .eb_retry: ; Form DAPA on stack + pushad push edx push eax - push es - push bx + push xfer_buf_seg + push 0 push word 1 ; Sector count push word 16 ; DAPA size + + ; check if we must do a RMW operation + cmp word [ADVSsz], 512 + je .no_rmw + cmp byte [ADVOp], 2 + je .no_rmw + + mov si,sp + mov dl,[ADVDrive] + mov ax,4200h + push ds + push ss + pop ds + int 13h + pop ds + jc .eb_error_stack + +.no_rmw: + ; modify sector with ADV + cld + push es + push xfer_buf_seg + pop es + push di + mov si, bx + mov cx, 256 + rep movsw + pop di + pop es + mov si,sp - pushad mov dl,[ADVDrive] mov ax,4000h or ah,[ADVOp] @@ -391,9 +441,24 @@ adv_read_write: pop ds int 13h pop ds - popad +.eb_error_stack: lea sp,[si+16] ; Remove DAPA + + popad jc .eb_error + + ; copy it back + pusha + push ds + mov si, di + mov di, bx + push xfer_buf_seg + pop ds + mov cx, 256 + rep movsw + pop ds + popa + pop si ret .eb_error: @@ -500,8 +565,11 @@ adv_read_write: alignz 8 ADVSec0 dq 0 ; Not specified ADVSec1 dq 0 ; Not specified +ADVOff0 dw 0 +ADVOff1 dw 0 ADVDrive db -1 ; No ADV defined ADVCHSInfo db -1 ; We have CHS info for this drive +ADVSsz dw 512 ; sector size section .bss16 ADVOp resb 1 diff --git a/dos/syslinux.c b/dos/syslinux.c index 6cd36d0..4b518c7 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -723,7 +723,7 @@ int main(int argc, char *argv[]) /* * Patch ldlinux.sys and the boot sector */ - i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, SECTOR_SIZE); + i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, SECTOR_SIZE, NULL); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* diff --git a/extlinux/main.c b/extlinux/main.c index e40b4d7..78fffae 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -228,11 +228,12 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) struct hd_geometry geo; sector_t *sectp; uint64_t totalbytes, totalsectors; - int nsect; + int nsect, nsect_full; struct fat_boot_sector *sbs; char *dirpath, *subpath, *xdirpath; int rv; unsigned sector_size; + uint16_t adv_offsets[2] = { 0, 0 }; dirpath = realpath(dir, NULL); if (!dirpath || stat(dir, &dirst)) { @@ -275,7 +276,8 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) dprintf("subpath = %s\n", subpath); totalbytes = get_size(devfd); - sector_size = get_sector_size(devfd); + /* FIXME support greater sector sizes for BTRFS */ + sector_size = fs_type == BTRFS ? SECTOR_SIZE : get_sector_size(devfd); get_geometry(devfd, totalbytes, sector_size, &geo); if (opt.heads) @@ -307,17 +309,22 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino); nsect = (boot_image_len + sector_size - 1) / sector_size; - nsect += 2; /* Two sectors for the ADV */ - sectp = alloca(sizeof(sector_t) * nsect); + nsect_full = (boot_image_len + 2 * ADV_SIZE + sector_size - 1) / sector_size; + sectp = alloca(sizeof(sector_t) * (nsect+2)); if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) { - if (sectmap(fd, sectp, nsect, sector_size)) { + if (sectmap(fd, sectp, nsect_full, sector_size)) { perror("bmap"); exit(1); } + sectp[nsect+1] = sectp[(boot_image_len + 1 * ADV_SIZE) / sector_size]; + sectp[nsect+0] = sectp[(boot_image_len + 0 * ADV_SIZE) / sector_size]; + adv_offsets[1] = (boot_image_len + 1 * ADV_SIZE) % sector_size; + adv_offsets[0] = (boot_image_len + 0 * ADV_SIZE) % sector_size; } else if (fs_type == BTRFS) { int i; sector_t *sp = sectp; +// FIXME ?? for (i = 0; i < nsect - 2; i++) *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i; for (i = 0; i < 2; i++) @@ -325,8 +332,9 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) } /* Create the modified image in memory */ - rv = syslinux_patch(sectp, nsect, opt.stupid_mode, - opt.raid_mode, subpath, subvol, sector_size); + rv = syslinux_patch(sectp, nsect + 2, opt.stupid_mode, + opt.raid_mode, subpath, subvol, sector_size, + adv_offsets); free(dirpath); return rv; @@ -410,7 +418,7 @@ int install_bootblock(int fd, const char *device) return 0; } -int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) +static int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) { char *file, *oldfile; int fd = -1, dirfd = -1; diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index 75ed451..d426839 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -50,6 +50,6 @@ typedef uint64_t sector_t; int syslinux_patch(const sector_t *sectors, int nsectors, int stupid, int raid_mode, const char *subdir, const char *subvol, - unsigned sector_size); + unsigned sector_size, uint16_t *adv_offsets); #endif diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index be101f9..222adb7 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -100,7 +100,7 @@ static inline void *ptr(void *img, uint16_t *offset_p) int syslinux_patch(const sector_t *sectp, int nsectors, int stupid, int raid_mode, const char *subdir, const char *subvol, - unsigned sector_size) + unsigned sector_size, uint16_t *adv_offsets) { struct patch_area *patcharea; struct ext_patch_area *epa; @@ -111,6 +111,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors, int i, dw, nptrs; struct fat_boot_sector *sbs = (struct fat_boot_sector *)boot_sector; uint64_t *advptrs; + uint16_t *advoffs; if (nsectors < nsect) return -1; /* The actual file is too small for content */ @@ -162,6 +163,11 @@ int syslinux_patch(const sector_t *sectp, int nsectors, advptrs = ptr(boot_image, &epa->advptroffset); set_64_sl(&advptrs[0], sectp[nsect-1-2]); set_64_sl(&advptrs[1], sectp[nsect-1-1]); + advoffs = (uint16_t *) (advptrs+2); + if (adv_offsets) { + set_16_sl(&advoffs[0], adv_offsets[0]); + set_16_sl(&advoffs[1], adv_offsets[1]); + } /* Poke in the base directory path */ if (subdir) { diff --git a/linux/syslinux.c b/linux/syslinux.c index 22983f9..7476be1 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -463,7 +463,7 @@ umount: * Patch ldlinux.sys and the boot sector */ i = syslinux_patch(sectors, ldlinux_sectors, opt.stupid_mode, - opt.raid_mode, subdir, NULL, SECTOR_SIZE); + opt.raid_mode, subdir, NULL, SECTOR_SIZE, NULL); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* diff --git a/mtools/syslinux.c b/mtools/syslinux.c index 6f3550f..a3c59cc 100755 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -273,7 +273,7 @@ int main(int argc, char *argv[]) /* Patch ldlinux.sys and the boot sector */ i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, - opt.directory, NULL, SECTOR_SIZE); + opt.directory, NULL, SECTOR_SIZE, NULL); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* Write the now-patched first sectors of ldlinux.sys */ diff --git a/win/syslinux.c b/win/syslinux.c index cbf003f..1cc8a4e 100644 --- a/win/syslinux.c +++ b/win/syslinux.c @@ -433,7 +433,7 @@ map_done: * Patch ldlinux.sys and the boot sector */ syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, - SECTOR_SIZE); + SECTOR_SIZE, NULL); /* * Rewrite the file -- 1.7.5.4
This set of patches add some support for sector size >512. Currently it fixes extlinux, MBR for GPT and ext partitions. Other code is unaffected. This set of patches has been tested on a read Dell machine running a beta firmware. Last patch is a workaround for a buggy BIOS but other systems are not affected.
after read_sector %edx:%eax are unused or incremented so increment always at end gaining 3 bytes Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- mbr/gptmbr.S | 19 ++++++++++--------- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S index ae0549f..ef2235d 100644 --- a/mbr/gptmbr.S +++ b/mbr/gptmbr.S @@ -142,7 +142,6 @@ next: pushw %bx get_ptab: call read_sector - call inc64 loopw get_ptab /* Find the boot partition */ @@ -240,16 +239,9 @@ saturate_stosl: ret /* - * Increment %edx:%eax - */ -inc64: - addl $1,%eax - adcl $0,%edx - ret - -/* * read_sector: read a single sector pointed to by %edx:%eax to * %es:%bx. CF is set on error. All registers saved. + * %edx:%eax and %es:%bx are incremented to read next sector */ read_sector: pushal @@ -282,6 +274,15 @@ read_common: popal jc disk_error addb $2, %bh /* bx += 512: point to the next buffer */ + + /* fall through and increment sector number */ + +/* + * Increment %edx:%eax + */ +inc64: + addl $1,%eax + adcl $0,%edx ret disk_error: -- 1.7.5.4
Frediano Ziglio
2012-Oct-03 14:26 UTC
[syslinux] [PATCH 2/9] Save some bytes adding a function to set bx before read_sector
Mostly of the time bx was set as phdr before calling read_sector so add a specific function to set %bx and call read_sector gaining 2 bytes Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- mbr/gptmbr.S | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S index ef2235d..f73b472 100644 --- a/mbr/gptmbr.S +++ b/mbr/gptmbr.S @@ -118,9 +118,7 @@ next: xorl %eax,%eax cltd incw %ax /* %edx:%eax = 1 */ - movw $phdr, %bx - pushw %bx /* -8(%bp) phdr == bootsect */ - call read_sector + call read_sector_phdr /* Number of partition sectors */ /* We assume the partition table is 32K or less, and that @@ -215,8 +213,7 @@ found_part: boot: movl (32+20)(%si),%eax movl (36+20)(%si),%edx - popw %bx - call read_sector + call read_sector_phdr cmpw $0xaa55, -2(%bx) jne missing_os /* Not a valid boot sector */ movw %bp, %sp /* driveno == bootsec-6 */ @@ -238,6 +235,11 @@ saturate_stosl: 1: stosl ret +read_sector_phdr: + movw $phdr, %bx + + /* fall through and read sector */ + /* * read_sector: read a single sector pointed to by %edx:%eax to * %es:%bx. CF is set on error. All registers saved. -- 1.7.5.4
Frediano Ziglio
2012-Oct-03 14:26 UTC
[syslinux] [PATCH 3/9] Reduce size reducing a message
Easy way to reduce code but actually I found the message is readable at the same way as previous. Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- mbr/gptmbr.S | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S index f73b472..b0c11b9 100644 --- a/mbr/gptmbr.S +++ b/mbr/gptmbr.S @@ -289,7 +289,7 @@ inc64: disk_error: call error - .ascii "Disk error on boot\r\n" + .ascii "Disk error\r\n" /* * Print error messages. This is invoked with "call", with the -- 1.7.5.4
If EBIOS is detected for this drive it tries to read sector size and use it. If error or no EBIOS 512 is assumed. Buffer to read sector size is always allocated into the stack. CHS informations are not readed as not needed and save space not restoring %dl for drive number. Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- mbr/gptmbr.S | 41 +++++++++++++++++++++++++++-------------- 1 files changed, 27 insertions(+), 14 deletions(-) diff --git a/mbr/gptmbr.S b/mbr/gptmbr.S index b0c11b9..88d2809 100644 --- a/mbr/gptmbr.S +++ b/mbr/gptmbr.S @@ -77,6 +77,12 @@ next: ADJUST_DRIVE pushw %dx /* 0(%bp) = %dl -> drive number */ + movw %sp, %bp /* %bp -> frame pointer: LEAVE UNCHANGED */ + + /* prepare to read sector size */ + sub $0x1c, %sp /* -28(%bp) == %sp */ + pushw $0x1e /* -30(%bp) == %sp */ + movw $0x200, -6(%bp) /* -6(%bp) sector size */ /* Check to see if we have EBIOS */ pushw %dx /* drive number */ @@ -86,6 +92,8 @@ next: xorb %dh, %dh stc int $0x13 + popw %dx /* restore drive */ + movb $0x08, %ah /* get CHS geometry */ jc 1f cmpw $0xaa55, %bx jne 1f @@ -97,22 +105,28 @@ next: movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \ (read_sector_cbios) -1: - popw %dx + /* + * read sector size. + * Should not fail but if it does I assume that at least + * previous 512 value is not overridden + */ + movb $0x48, %ah + movw %sp, %si +1: /* Get (C)HS geometry */ - movb $0x08, %ah int $0x13 + + /* here we computer CHS values or just do some dummy computation for EBIOS */ andw $0x3f, %cx /* Sector count */ - movw %sp, %bp /* %bp -> frame pointer: LEAVE UNCHANGED */ - pushw %cx /* -2(%bp) Save sectors on the stack */ + pushw %cx /* -32(%bp) Save sectors on the stack */ movzbw %dh, %ax /* dh = max head */ incw %ax /* From 0-based max to count */ mulw %cx /* Heads*sectors -> sectors per cylinder */ /* Save sectors/cylinder on the stack */ - pushw %dx /* -4(%bp) High word */ - pushw %ax /* -6(%bp) Low word */ + pushw %dx /* -34(%bp) High word */ + pushw %ax /* -36(%bp) Low word */ /* Load partition table header */ xorl %eax,%eax @@ -121,15 +135,14 @@ next: call read_sector_phdr /* Number of partition sectors */ - /* We assume the partition table is 32K or less, and that - the sector size is 512. */ + /* We assume the partition table is 32K or less */ /* Note: phdr == 6(%bp) */ movw (80+6)(%bp),%cx /* NumberOfPartitionEntries */ movw (84+6)(%bp),%ax /* SizeOfPartitionEntry */ pushw %ax pushw %cx mulw %cx - shrw $9,%ax + divw -6(%bp) /* %dx == 0 here */ xchgw %ax,%cx incw %cx @@ -214,7 +227,7 @@ boot: movl (32+20)(%si),%eax movl (36+20)(%si),%edx call read_sector_phdr - cmpw $0xaa55, -2(%bx) + cmpw $0xaa55, (0x7c00+0x1fe) jne missing_os /* Not a valid boot sector */ movw %bp, %sp /* driveno == bootsec-6 */ popw %dx /* dl -> drive number */ @@ -258,12 +271,12 @@ read_sector: /* This chunk is skipped if we have ebios */ /* Do not clobber %es:%bx or %edx:%eax before this chunk! */ read_sector_cbios: - divl -6(%bp) /* secpercyl */ + divl -36(%bp) /* secpercyl */ shlb $6, %ah movb %ah, %cl movb %al, %ch xchgw %dx, %ax - divb -2(%bp) /* sectors */ + divb -32(%bp) /* sectors */ movb %al, %dh orb %ah, %cl incw %cx /* Sectors are 1-based */ @@ -275,7 +288,7 @@ read_common: leaw 16(%si), %sp /* Drop DAPA */ popal jc disk_error - addb $2, %bh /* bx += 512: point to the next buffer */ + addb -5(%bp), %bh /* bx += sector size: point to the next buffer */ /* fall through and increment sector number */ -- 1.7.5.4
Limit some function visibility in extlinux. Also reamore an unused NADV define. Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- extlinux/main.c | 8 ++++---- libinstaller/syslxmod.c | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/extlinux/main.c b/extlinux/main.c index 73f3fbe..f0d8e11 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -76,7 +76,7 @@ static char subvol[BTRFS_SUBVOL_MAX]; /* * Get the size of a block device */ -uint64_t get_size(int devfd) +static uint64_t get_size(int devfd) { uint64_t bytes; uint32_t sects; @@ -210,7 +210,7 @@ ok: * * Returns the number of modified bytes in the boot file. */ -int patch_file_and_bootblock(int fd, const char *dir, int devfd) +static int patch_file_and_bootblock(int fd, const char *dir, int devfd) { struct stat dirst, xdst; struct hd_geometry geo; @@ -746,7 +746,7 @@ static char * get_default_subvol(char * rootdir, char * subvol) return subvol; } -int install_file(const char *path, int devfd, struct stat *rst) +static int install_file(const char *path, int devfd, struct stat *rst) { if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) return ext2_fat_install_file(path, devfd, rst); @@ -1174,7 +1174,7 @@ static int ext_write_adv(const char *path, const char *cfg, int devfd) return write_adv(path, cfg); } -int install_loader(const char *path, int update_only) +static int install_loader(const char *path, int update_only) { struct stat st, fst; int devfd, rv; diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index 2436845..c706f2c 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -96,8 +96,6 @@ static inline void *ptr(void *img, uint16_t *offset_p) * Returns the number of modified bytes in ldlinux.sys if successful, * otherwise -1. */ -#define NADV 2 - int syslinux_patch(const sector_t *sectp, int nsectors, int stupid, int raid_mode, const char *subdir, const char *subvol) -- 1.7.5.4
Frediano Ziglio
2012-Oct-03 14:26 UTC
[syslinux] [PATCH 6/9] Make sector size dynamic in extlinux
Instead of using SECTOR_SIZE as a constant everywhere pass the sector size to syslinux_patch. This patch compute read sector size only in extlinux. Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- dos/syslinux.c | 2 +- extlinux/main.c | 36 +++++++++++++++++++++++++----------- libinstaller/syslinux.h | 3 ++- libinstaller/syslxcom.c | 30 +++++++++++++++--------------- libinstaller/syslxcom.h | 2 +- libinstaller/syslxmod.c | 14 ++++++++------ linux/syslinux.c | 4 ++-- mtools/syslinux.c | 2 +- win/syslinux.c | 3 ++- 9 files changed, 57 insertions(+), 39 deletions(-) diff --git a/dos/syslinux.c b/dos/syslinux.c index fa4bf38..6cd36d0 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -723,7 +723,7 @@ int main(int argc, char *argv[]) /* * Patch ldlinux.sys and the boot sector */ - i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL); + i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, SECTOR_SIZE); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* diff --git a/extlinux/main.c b/extlinux/main.c index f0d8e11..e40b4d7 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -95,6 +95,18 @@ static uint64_t get_size(int devfd) } /* + * Get sector size + */ +static unsigned get_sector_size(int devfd) +{ + int size; + + if (!ioctl(devfd, BLKSSZGET, &size)) + return size; + return SECTOR_SIZE; +} + +/* * Get device geometry and partition offset */ struct geometry_table { @@ -145,7 +157,7 @@ static const struct geometry_table standard_geometries[] = { {0, {0, 0, 0, 0}} }; -int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) +static int get_geometry(int devfd, uint64_t totalbytes, unsigned sector_size, struct hd_geometry *geo) { struct floppy_struct fd_str; struct loop_info li; @@ -179,7 +191,7 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) geo->heads = opt.heads ? : 64; geo->sectors = opt.sectors ? : 32; - geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT); + geo->cylinders = totalbytes / (geo->heads * geo->sectors * sector_size); geo->start = 0; if (!opt.sectors && !opt.heads) { @@ -193,11 +205,11 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) ok: /* If this is a loopback device, try to set the start */ if (!ioctl(devfd, LOOP_GET_STATUS64, &li64)) - geo->start = li64.lo_offset >> SECTOR_SHIFT; + geo->start = li64.lo_offset / sector_size; else if (!ioctl(devfd, LOOP_GET_STATUS, &li)) - geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT; + geo->start = (unsigned int)li.lo_offset / sector_size; else if (!sysfs_get_offset(devfd, &geo->start)) { - /* OK */ + geo->start /= (sector_size / SECTOR_SIZE); } return rv; @@ -220,6 +232,7 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) struct fat_boot_sector *sbs; char *dirpath, *subpath, *xdirpath; int rv; + unsigned sector_size; dirpath = realpath(dir, NULL); if (!dirpath || stat(dir, &dirst)) { @@ -262,7 +275,8 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) dprintf("subpath = %s\n", subpath); totalbytes = get_size(devfd); - get_geometry(devfd, totalbytes, &geo); + sector_size = get_sector_size(devfd); + get_geometry(devfd, totalbytes, sector_size, &geo); if (opt.heads) geo.heads = opt.heads; @@ -276,7 +290,7 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) sbs = (struct fat_boot_sector *)syslinux_bootsect; - totalsectors = totalbytes >> SECTOR_SHIFT; + totalsectors = totalbytes / sector_size; if (totalsectors >= 65536) { set_16(&sbs->bsSectors, 0); } else { @@ -284,7 +298,7 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) } set_32(&sbs->bsHugeSectors, totalsectors); - set_16(&sbs->bsBytesPerSec, SECTOR_SIZE); + set_16(&sbs->bsBytesPerSec, sector_size); set_16(&sbs->bsSecPerTrack, geo.sectors); set_16(&sbs->bsHeads, geo.heads); set_32(&sbs->bsHiddenSecs, geo.start); @@ -292,11 +306,11 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) /* Construct the boot file map */ dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino); - nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + nsect = (boot_image_len + sector_size - 1) / sector_size; nsect += 2; /* Two sectors for the ADV */ sectp = alloca(sizeof(sector_t) * nsect); if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) { - if (sectmap(fd, sectp, nsect)) { + if (sectmap(fd, sectp, nsect, sector_size)) { perror("bmap"); exit(1); } @@ -312,7 +326,7 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) /* Create the modified image in memory */ rv = syslinux_patch(sectp, nsect, opt.stupid_mode, - opt.raid_mode, subpath, subvol); + opt.raid_mode, subpath, subvol, sector_size); free(dirpath); return rv; diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index 8b86f88..75ed451 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -49,6 +49,7 @@ const char *syslinux_check_bootsect(const void *bs, int *fs_type); typedef uint64_t sector_t; int syslinux_patch(const sector_t *sectors, int nsectors, int stupid, int raid_mode, - const char *subdir, const char *subvol); + const char *subdir, const char *subvol, + unsigned sector_size); #endif diff --git a/libinstaller/syslxcom.c b/libinstaller/syslxcom.c index 57f13cd..95a7110 100644 --- a/libinstaller/syslxcom.c +++ b/libinstaller/syslxcom.c @@ -45,8 +45,6 @@ int fs_type; # define dprintf(...) ((void)0) #endif -#define SECTOR_SHIFT 9 - static void die(const char *msg) { fputs(msg, stderr); @@ -176,7 +174,7 @@ void set_attributes(int fd) } /* New FIEMAP based mapping */ -static int sectmap_fie(int fd, sector_t *sectors, int nsectors) +static int sectmap_fie(int fd, sector_t *sectors, int nsectors, unsigned sector_size) { struct fiemap *fm; struct fiemap_extent *fe; @@ -193,7 +191,7 @@ static int sectmap_fie(int fd, sector_t *sectors, int nsectors) memset(fm, 0, sizeof *fm); - maplen = (uint64_t)nsectors << SECTOR_SHIFT; + maplen = (uint64_t)nsectors * sector_size; if (maplen > (uint64_t)st.st_size) maplen = st.st_size; @@ -217,12 +215,12 @@ static int sectmap_fie(int fd, sector_t *sectors, int nsectors) for (i = 0; i < fm->fm_mapped_extents; i++) { if (fe->fe_flags & FIEMAP_EXTENT_LAST) { /* If this is the *final* extent, pad the length */ - fe->fe_length = (fe->fe_length + SECTOR_SIZE - 1) - & ~(SECTOR_SIZE - 1); + fe->fe_length = (fe->fe_length + sector_size - 1) + & ~(sector_size - 1); } if ((fe->fe_logical | fe->fe_physical| fe->fe_length) & - (SECTOR_SIZE - 1)) + (sector_size - 1)) return -1; if (fe->fe_flags & (FIEMAP_EXTENT_UNKNOWN| @@ -232,9 +230,9 @@ static int sectmap_fie(int fd, sector_t *sectors, int nsectors) FIEMAP_EXTENT_UNWRITTEN)) return -1; - secp = sectors + (fe->fe_logical >> SECTOR_SHIFT); - sec = fe->fe_physical >> SECTOR_SHIFT; - nsec = fe->fe_length >> SECTOR_SHIFT; + secp = sectors + (fe->fe_logical / sector_size); + sec = fe->fe_physical / sector_size; + nsec = fe->fe_length / sector_size; while (nsec--) { if (secp >= esec) @@ -249,7 +247,7 @@ static int sectmap_fie(int fd, sector_t *sectors, int nsectors) } /* Legacy FIBMAP based mapping */ -static int sectmap_fib(int fd, sector_t *sectors, int nsectors) +static int sectmap_fib(int fd, sector_t *sectors, int nsectors, unsigned sector_size) { unsigned int blk, nblk; unsigned int i; @@ -261,7 +259,9 @@ static int sectmap_fib(int fd, sector_t *sectors, int nsectors) return -1; /* Number of sectors per block */ - blksize >>= SECTOR_SHIFT; + blksize /= sector_size; + if (blksize == 0) + return -1; nblk = 0; while (nsectors) { @@ -283,12 +283,12 @@ static int sectmap_fib(int fd, sector_t *sectors, int nsectors) /* * Produce file map */ -int sectmap(int fd, sector_t *sectors, int nsectors) +int sectmap(int fd, sector_t *sectors, int nsectors, unsigned sector_size) { - if (!sectmap_fie(fd, sectors, nsectors)) + if (!sectmap_fie(fd, sectors, nsectors, sector_size)) return 0; - return sectmap_fib(fd, sectors, nsectors); + return sectmap_fib(fd, sectors, nsectors, sector_size); } /* diff --git a/libinstaller/syslxcom.h b/libinstaller/syslxcom.h index 8b3b461..111b634 100644 --- a/libinstaller/syslxcom.h +++ b/libinstaller/syslxcom.h @@ -8,7 +8,7 @@ ssize_t xpread(int fd, void *buf, size_t count, off_t offset); ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset); void clear_attributes(int fd); void set_attributes(int fd); -int sectmap(int fd, sector_t *sectors, int nsectors); +int sectmap(int fd, sector_t *sectors, int nsectors, unsigned sector_size); int syslinux_already_installed(int dev_fd); #endif diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index c706f2c..be101f9 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -31,7 +31,8 @@ * Generate sector extents */ static void generate_extents(struct syslinux_extent *ex, int nptrs, - const sector_t *sectp, int nsect) + const sector_t *sectp, int nsect, + unsigned sector_size) { uint32_t addr = 0x8000; /* ldlinux.sys starts loading here */ uint32_t base; @@ -47,7 +48,7 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs, sect = *sectp++; if (len) { - uint32_t xbytes = (len + 1) * SECTOR_SIZE; + uint32_t xbytes = (len + 1) * sector_size; if (sect == lba + len && xbytes < 65536 && ((addr ^ (base + xbytes - 1)) & 0xffff0000) == 0) { @@ -66,7 +67,7 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs, len = 1; next: - addr += SECTOR_SIZE; + addr += sector_size; nsect--; } @@ -98,13 +99,14 @@ static inline void *ptr(void *img, uint16_t *offset_p) */ int syslinux_patch(const sector_t *sectp, int nsectors, int stupid, int raid_mode, - const char *subdir, const char *subvol) + const char *subdir, const char *subvol, + unsigned sector_size) { 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; + int nsect = ((boot_image_len + sector_size - 1) / sector_size) + 2; uint32_t csum; int i, dw, nptrs; struct fat_boot_sector *sbs = (struct fat_boot_sector *)boot_sector; @@ -154,7 +156,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors, } /* -1 for the pointer in the boot sector, -2 for the two ADVs */ - generate_extents(ex, nptrs, sectp, nsect-1-2); + generate_extents(ex, nptrs, sectp, nsect-1-2, sector_size); /* ADV pointers */ advptrs = ptr(boot_image, &epa->advptroffset); diff --git a/linux/syslinux.c b/linux/syslinux.c index 4b13b7f..22983f9 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -444,7 +444,7 @@ int main(int argc, char *argv[]) */ ldlinux_sectors += 2; /* 2 ADV sectors */ sectors = calloc(ldlinux_sectors, sizeof *sectors); - if (sectmap(fd, sectors, ldlinux_sectors)) { + if (sectmap(fd, sectors, ldlinux_sectors, SECTOR_SIZE)) { perror("bmap"); exit(1); } @@ -463,7 +463,7 @@ umount: * Patch ldlinux.sys and the boot sector */ i = syslinux_patch(sectors, ldlinux_sectors, opt.stupid_mode, - opt.raid_mode, subdir, NULL); + opt.raid_mode, subdir, NULL, SECTOR_SIZE); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* diff --git a/mtools/syslinux.c b/mtools/syslinux.c index c65021b..6f3550f 100755 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -273,7 +273,7 @@ int main(int argc, char *argv[]) /* Patch ldlinux.sys and the boot sector */ i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, - opt.directory, NULL); + opt.directory, NULL, SECTOR_SIZE); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* Write the now-patched first sectors of ldlinux.sys */ diff --git a/win/syslinux.c b/win/syslinux.c index 669450e..cbf003f 100644 --- a/win/syslinux.c +++ b/win/syslinux.c @@ -432,7 +432,8 @@ map_done: /* * Patch ldlinux.sys and the boot sector */ - syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL); + syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, + SECTOR_SIZE); /* * Rewrite the file -- 1.7.5.4
Instead of assuming that sector size is always 512 add a function that take byte offsets instead of number of sectors and call it when needed a specific range of bytes (for instance to read partition headers). Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- core/fs/diskio.c | 80 +++++++++++++++++++++++++++++++++++++++++++-- core/fs/ext2/ext2.c | 2 +- core/fs/fat/fat.c | 2 +- core/fs/iso9660/iso9660.c | 8 ++-- core/fs/ntfs/ntfs.c | 4 +- core/include/disk.h | 2 + 6 files changed, 87 insertions(+), 11 deletions(-) diff --git a/core/fs/diskio.c b/core/fs/diskio.c index 6683816..7e58d6f 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -265,6 +265,80 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, return done; } +#define rdwr_sectors0(buf, lba, count, is_write) \ + disk->rdwr_sectors(disk, buf, lba, count, is_write) +/* + * Read a range of bytes + */ +int rdwr_bytes(struct disk *disk, void *buf, + bytes_t lba, size_t count, bool is_write) +{ + int done, res; + unsigned mask, before, len; + unsigned shift = disk->sector_shift; + + dprintf("called rdwr_bytes from %llu for %u bytes\n", (unsigned long long) lba, (unsigned) count); + + mask = disk->sector_size - 1; + + /* aligned, fix count/lba */ + if (((lba|count) & mask) == 0) { + return (rdwr_sectors0(buf, lba >> shift, count >> shift, is_write) << shift); + } + + /* do the hard work */ + done = 0; + if ((lba & mask) != 0) { + /* align start sector */ + before = lba & mask; + len = disk->sector_size - before; + if (len > count) len = count; + res = rdwr_sectors0(core_xfer_buf, lba >> shift, 1, 0); + if (!res) return done; + if (is_write) { + memcpy(core_xfer_buf + before, buf, len); + res = rdwr_sectors0(core_xfer_buf, lba >> shift, 1, 1); + if (!res) return done; + } else { + memcpy(buf, core_xfer_buf + before, len); + } + buf += len; + lba += len; + count -= len; + done += len; + } + + /* read/write full sectors */ + len = count >> shift; + if (len) { + res = rdwr_sectors0(buf, lba >> shift, len, is_write) << shift; + done += res; + len <<= shift; + if (res < len) return done; + lba += len; + count -= len; + done += len; + buf += len; + } + + /* last partial sector */ + if (count) { + len = count; + res = rdwr_sectors0(core_xfer_buf, lba >> shift, 1, 0); + if (!res) return done; + if (is_write) { + memcpy(core_xfer_buf, buf, len); + res = rdwr_sectors0(core_xfer_buf, lba >> shift, 1, 1); + if (!res) return done; + } else { + memcpy(buf, core_xfer_buf, len); + } + done += len; + } + + return done; +} + struct edd_disk_params { uint16_t len; uint16_t flags; @@ -292,9 +366,7 @@ static inline bool is_power_of_2(uint32_t x) void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) { - int sec_per_block = block_size / disk->sector_size; - - disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0); + rdwr_bytes(disk, buf, (bytes_t)block * block_size, block_size, 0); } @@ -373,6 +445,8 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, is_power_of_2(edd_params.sector_size)) sector_size = edd_params.sector_size; } + if (hard_max_transfer > (0x10000/sector_size)) + hard_max_transfer = (0x10000/sector_size); } } diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c index 3bfbb7a..8f0f2a4 100644 --- a/core/fs/ext2/ext2.c +++ b/core/fs/ext2/ext2.c @@ -276,7 +276,7 @@ static int ext2_fs_init(struct fs_info *fs) struct cache *cs; /* read the super block */ - disk->rdwr_sectors(disk, &sb, 2, 2, 0); + rdwr_bytes(disk, &sb, 2*512, 2*512, 0); /* check if it is ext2, since we also support btrfs now */ if (sb.s_magic != EXT2_SUPER_MAGIC) diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c index b08923c..3c7620e 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -731,7 +731,7 @@ static int vfat_fs_init(struct fs_info *fs) fs->sector_size = 1 << fs->sector_shift; fs->block_size = 1 << fs->block_shift; - disk->rdwr_sectors(disk, &fat, 0, 1, 0); + rdwr_bytes(disk, &fat, 0, 512, 0); /* XXX: Find better sanity checks... */ if (!fat.bxResSectors || !fat.bxFATs) diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c index 3cd3ac4..60b3b55 100644 --- a/core/fs/iso9660/iso9660.c +++ b/core/fs/iso9660/iso9660.c @@ -251,7 +251,7 @@ static int iso_fs_init(struct fs_info *fs) char pvd[2048]; /* Primary Volume Descriptor */ uint32_t pvd_lba; struct disk *disk = fs->fs_dev->disk; - int blktosec; + int blkshift; sbi = malloc(sizeof(*sbi)); if (!sbi) { @@ -268,14 +268,14 @@ static int iso_fs_init(struct fs_info *fs) fs->block_shift = 11; /* A CD-ROM block is always 2K */ fs->sector_size = 1 << fs->sector_shift; fs->block_size = 1 << fs->block_shift; - blktosec = fs->block_shift - fs->sector_shift; + blkshift = fs->block_shift; pvd_lba = iso_boot_info.pvd; if (!pvd_lba) pvd_lba = 16; /* Default if not otherwise defined */ - disk->rdwr_sectors(disk, pvd, (sector_t)pvd_lba << blktosec, - 1 << blktosec, false); + rdwr_bytes(disk, pvd, (bytes_t)pvd_lba << blkshift, + 1 << blkshift, false); memcpy(&sbi->root, pvd + ROOT_DIR_OFFSET, sizeof(sbi->root)); /* Initialize the cache */ diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c index 500d0fd..f6c8e24 100644 --- a/core/fs/ntfs/ntfs.c +++ b/core/fs/ntfs/ntfs.c @@ -1311,8 +1311,8 @@ static int ntfs_fs_init(struct fs_info *fs) dprintf("in %s()\n", __func__); - read_count = disk->rdwr_sectors(disk, &ntfs, 0, 1, 0); - if (!read_count) + read_count = rdwr_bytes(disk, &ntfs, 0, 512, 0); + if (read_count != 512) return -1; if (!ntfs_check_sb_fields(&ntfs)) diff --git a/core/include/disk.h b/core/include/disk.h index ac23e92..f0a3fa8 100644 --- a/core/include/disk.h +++ b/core/include/disk.h @@ -7,6 +7,7 @@ typedef uint64_t sector_t; typedef uint64_t block_t; +typedef uint64_t bytes_t; /* * struct disk: contains the information about a specific disk and also @@ -29,6 +30,7 @@ struct disk { extern void read_sectors(char *, sector_t, int); extern void getoneblk(struct disk *, char *, block_t, int); +extern int rdwr_bytes(struct disk *, void *, bytes_t, size_t, bool); /* diskio.c */ struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t); -- 1.7.5.4
Add offset to adv sectors. If sector size is greater than adv size you need an additional offset to specify which sector part contains the information. This patch does not support BTRFS (that will work only using 512 as sector size). Signed-off-by: Frediano Ziglio <frediano.ziglio at citrix.com> --- core/adv.inc | 76 ++++++++++++++++++++++++++++++++++++++++++++-- dos/syslinux.c | 2 +- extlinux/main.c | 24 ++++++++++----- libinstaller/syslinux.h | 2 +- libinstaller/syslxmod.c | 8 ++++- linux/syslinux.c | 2 +- mtools/syslinux.c | 2 +- win/syslinux.c | 2 +- 8 files changed, 100 insertions(+), 18 deletions(-) diff --git a/core/adv.inc b/core/adv.inc index 0b45a6c..a714800 100644 --- a/core/adv.inc +++ b/core/adv.inc @@ -356,11 +356,13 @@ adv_read_write: mov eax,[ADVSec0] mov edx,[ADVSec0+4] + mov di,[ADVOff0] mov bx,adv0 call .doone mov eax,[ADVSec1] mov edx,[ADVSec1+4] + mov di,[ADVOff1] mov bx,adv1 call .doone @@ -371,18 +373,66 @@ adv_read_write: push si jmp si + extern xfer_buf_seg .ebios: + pusha + sub sp,1ch + push 1eh + mov si,sp + mov ah,48h ; EDD get drive parameters + mov dl,[ADVDrive] + push ds + push ss + pop ds + mov word [si+18h], 512 + int 13h + mov ax, [si+18h] + pop ds + mov [ADVSsz], ax + add sp,1eh + popa + mov cx,adv_retries .eb_retry: ; Form DAPA on stack + pushad push edx push eax - push es - push bx + push xfer_buf_seg + push 0 push word 1 ; Sector count push word 16 ; DAPA size + + ; check if we must do a RMW operation + cmp word [ADVSsz], 512 + je .no_rmw + cmp byte [ADVOp], 2 + je .no_rmw + + mov si,sp + mov dl,[ADVDrive] + mov ax,4200h + push ds + push ss + pop ds + int 13h + pop ds + jc .eb_error_stack + +.no_rmw: + ; modify sector with ADV + cld + push es + push xfer_buf_seg + pop es + push di + mov si, bx + mov cx, 256 + rep movsw + pop di + pop es + mov si,sp - pushad mov dl,[ADVDrive] mov ax,4000h or ah,[ADVOp] @@ -391,9 +441,24 @@ adv_read_write: pop ds int 13h pop ds - popad +.eb_error_stack: lea sp,[si+16] ; Remove DAPA + + popad jc .eb_error + + ; copy it back + pusha + push ds + mov si, di + mov di, bx + push xfer_buf_seg + pop ds + mov cx, 256 + rep movsw + pop ds + popa + pop si ret .eb_error: @@ -500,8 +565,11 @@ adv_read_write: alignz 8 ADVSec0 dq 0 ; Not specified ADVSec1 dq 0 ; Not specified +ADVOff0 dw 0 +ADVOff1 dw 0 ADVDrive db -1 ; No ADV defined ADVCHSInfo db -1 ; We have CHS info for this drive +ADVSsz dw 512 ; sector size section .bss16 ADVOp resb 1 diff --git a/dos/syslinux.c b/dos/syslinux.c index 6cd36d0..4b518c7 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -723,7 +723,7 @@ int main(int argc, char *argv[]) /* * Patch ldlinux.sys and the boot sector */ - i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, SECTOR_SIZE); + i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, SECTOR_SIZE, NULL); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* diff --git a/extlinux/main.c b/extlinux/main.c index e40b4d7..78fffae 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -228,11 +228,12 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) struct hd_geometry geo; sector_t *sectp; uint64_t totalbytes, totalsectors; - int nsect; + int nsect, nsect_full; struct fat_boot_sector *sbs; char *dirpath, *subpath, *xdirpath; int rv; unsigned sector_size; + uint16_t adv_offsets[2] = { 0, 0 }; dirpath = realpath(dir, NULL); if (!dirpath || stat(dir, &dirst)) { @@ -275,7 +276,8 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) dprintf("subpath = %s\n", subpath); totalbytes = get_size(devfd); - sector_size = get_sector_size(devfd); + /* FIXME support greater sector sizes for BTRFS */ + sector_size = fs_type == BTRFS ? SECTOR_SIZE : get_sector_size(devfd); get_geometry(devfd, totalbytes, sector_size, &geo); if (opt.heads) @@ -307,17 +309,22 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino); nsect = (boot_image_len + sector_size - 1) / sector_size; - nsect += 2; /* Two sectors for the ADV */ - sectp = alloca(sizeof(sector_t) * nsect); + nsect_full = (boot_image_len + 2 * ADV_SIZE + sector_size - 1) / sector_size; + sectp = alloca(sizeof(sector_t) * (nsect+2)); if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) { - if (sectmap(fd, sectp, nsect, sector_size)) { + if (sectmap(fd, sectp, nsect_full, sector_size)) { perror("bmap"); exit(1); } + sectp[nsect+1] = sectp[(boot_image_len + 1 * ADV_SIZE) / sector_size]; + sectp[nsect+0] = sectp[(boot_image_len + 0 * ADV_SIZE) / sector_size]; + adv_offsets[1] = (boot_image_len + 1 * ADV_SIZE) % sector_size; + adv_offsets[0] = (boot_image_len + 0 * ADV_SIZE) % sector_size; } else if (fs_type == BTRFS) { int i; sector_t *sp = sectp; +// FIXME ?? for (i = 0; i < nsect - 2; i++) *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i; for (i = 0; i < 2; i++) @@ -325,8 +332,9 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) } /* Create the modified image in memory */ - rv = syslinux_patch(sectp, nsect, opt.stupid_mode, - opt.raid_mode, subpath, subvol, sector_size); + rv = syslinux_patch(sectp, nsect + 2, opt.stupid_mode, + opt.raid_mode, subpath, subvol, sector_size, + adv_offsets); free(dirpath); return rv; @@ -410,7 +418,7 @@ int install_bootblock(int fd, const char *device) return 0; } -int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) +static int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) { char *file, *oldfile; int fd = -1, dirfd = -1; diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index 75ed451..d426839 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -50,6 +50,6 @@ typedef uint64_t sector_t; int syslinux_patch(const sector_t *sectors, int nsectors, int stupid, int raid_mode, const char *subdir, const char *subvol, - unsigned sector_size); + unsigned sector_size, uint16_t *adv_offsets); #endif diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index be101f9..222adb7 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -100,7 +100,7 @@ static inline void *ptr(void *img, uint16_t *offset_p) int syslinux_patch(const sector_t *sectp, int nsectors, int stupid, int raid_mode, const char *subdir, const char *subvol, - unsigned sector_size) + unsigned sector_size, uint16_t *adv_offsets) { struct patch_area *patcharea; struct ext_patch_area *epa; @@ -111,6 +111,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors, int i, dw, nptrs; struct fat_boot_sector *sbs = (struct fat_boot_sector *)boot_sector; uint64_t *advptrs; + uint16_t *advoffs; if (nsectors < nsect) return -1; /* The actual file is too small for content */ @@ -162,6 +163,11 @@ int syslinux_patch(const sector_t *sectp, int nsectors, advptrs = ptr(boot_image, &epa->advptroffset); set_64_sl(&advptrs[0], sectp[nsect-1-2]); set_64_sl(&advptrs[1], sectp[nsect-1-1]); + advoffs = (uint16_t *) (advptrs+2); + if (adv_offsets) { + set_16_sl(&advoffs[0], adv_offsets[0]); + set_16_sl(&advoffs[1], adv_offsets[1]); + } /* Poke in the base directory path */ if (subdir) { diff --git a/linux/syslinux.c b/linux/syslinux.c index 22983f9..7476be1 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -463,7 +463,7 @@ umount: * Patch ldlinux.sys and the boot sector */ i = syslinux_patch(sectors, ldlinux_sectors, opt.stupid_mode, - opt.raid_mode, subdir, NULL, SECTOR_SIZE); + opt.raid_mode, subdir, NULL, SECTOR_SIZE, NULL); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* diff --git a/mtools/syslinux.c b/mtools/syslinux.c index 6f3550f..a3c59cc 100755 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -273,7 +273,7 @@ int main(int argc, char *argv[]) /* Patch ldlinux.sys and the boot sector */ i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, - opt.directory, NULL, SECTOR_SIZE); + opt.directory, NULL, SECTOR_SIZE, NULL); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* Write the now-patched first sectors of ldlinux.sys */ diff --git a/win/syslinux.c b/win/syslinux.c index cbf003f..1cc8a4e 100644 --- a/win/syslinux.c +++ b/win/syslinux.c @@ -433,7 +433,7 @@ map_done: * Patch ldlinux.sys and the boot sector */ syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL, - SECTOR_SIZE); + SECTOR_SIZE, NULL); /* * Rewrite the file -- 1.7.5.4
On Thu, 2013-12-12 at 20:29 -0800, H. Peter Anvin wrote:> On 10/03/2012 07:26 AM, Frediano Ziglio wrote: > > This set of patches add some support for sector size >512. > > Currently it fixes extlinux, MBR for GPT and ext partitions. > > Other code is unaffected. > > > > This set of patches has been tested on a read Dell machine running a beta > > firmware. > > > > Last patch is a workaround for a buggy BIOS but other systems are not > > affected. > > > > What is the baseline for this patchset? > > -hpa >Surely should apply to 4.xx where they was developed but I think I send them for 5.xx. mbr part of patches was merged time ago. Unfortunately I had no time to update other patches. If I remember there was a problem on the way ADV was implemented (using the same sector). Unfortunately my company business required to work on other things. We actually have these patches in our product but would be very great to upstream them. Do you need some help testing? I should have some patches (like seabios) somewhere. Frediano
On 12/16/2013 05:18 AM, Frediano Ziglio wrote:> > Surely should apply to 4.xx where they was developed but I think I send > them for 5.xx. mbr part of patches was merged time ago. > Unfortunately I had no time to update other patches. If I remember there > was a problem on the way ADV was implemented (using the same sector). > > Unfortunately my company business required to work on other things. We > actually have these patches in our product but would be very great to > upstream them. > > Do you need some help testing? I should have some patches (like seabios) > somewhere. >That might help, but yes, there are certainly issues with the ADV (I think we should expand the ADV to 4K, but that means we need to do some size reduction to fit the btrfs area). -hpa
Possibly Parallel Threads
- [PATCH 0/9] linux/syslinux: support ext2/3/4 device
- [PATCH 0/8] extlinux: support unmounted ext2/3/4 filesystem
- [PATCH 1/3] ALPHA: make sector size dynamic in extlinux
- [PATCH 4/5] installers: fix a possible buffer overflow when looking for LDLINUX_MAGIC
- [PATCH 0/2] UFS1/2 support series