Frediano Ziglio
2013-Feb-13 16:51 UTC
[syslinux] [PATCH] 4k_sector: Support dynamic sectors in ext partitions
This patches add support for dynamic sectors to ext partitions. Instead of assuming sector size constans is computed. ldlinux already use sector size dynamically. Change code that rely on sector size == 512 using a new function that accept bytes as argument instead of sectors.
Frediano Ziglio
2013-Feb-13 16:51 UTC
[syslinux] [PATCH 1/3] 4k_sector: 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 63a3a85..4d699f1 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -729,7 +729,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 aa20e1b..be1e13d 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -107,6 +107,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 { @@ -157,7 +169,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; @@ -191,7 +203,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) { @@ -205,11 +217,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; @@ -232,6 +244,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)) { @@ -274,7 +287,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; @@ -288,7 +302,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 { @@ -296,7 +310,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); @@ -304,12 +318,12 @@ 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 || fs_type == XFS) { - if (sectmap(fd, sectp, nsect)) { + if (sectmap(fd, sectp, nsect, sector_size)) { perror("bmap"); exit(1); } @@ -325,7 +339,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 f60a066..9e1aef2 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -52,6 +52,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 98e2710..14d8f8e 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; @@ -156,7 +158,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors, #endif /* -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 f4749ea..5e2188e 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -454,7 +454,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); } @@ -498,7 +498,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 f43b5a5..66d53d2 100755 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -331,7 +331,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 c291f00..9392d23 100644 --- a/win/syslinux.c +++ b/win/syslinux.c @@ -487,7 +487,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.9.5
Frediano Ziglio
2013-Feb-13 16:51 UTC
[syslinux] [PATCH 2/3] 4k_sector: Implement and use rdwr_bytes
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 957c60b..8f169a9 100644 --- a/core/fs/ext2/ext2.c +++ b/core/fs/ext2/ext2.c @@ -277,7 +277,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 b2c20ee..8bd5652 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 fe58a5b..9dbcce3 100644 --- a/core/fs/iso9660/iso9660.c +++ b/core/fs/iso9660/iso9660.c @@ -252,7 +252,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) { @@ -269,14 +269,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 f54df7e..8b39739 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.9.5
Frediano Ziglio
2013-Feb-13 16:51 UTC
[syslinux] [PATCH 3/3] 4k_sector: Fix ADV in adv.inc
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 | 77 ++++++++++++++++++++++++++++++++++++++++++++--- dos/syslinux.c | 2 +- extlinux/main.c | 23 +++++++++----- 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..ab29fde 100644 --- a/core/adv.inc +++ b/core/adv.inc @@ -351,16 +351,35 @@ adv_read_write: jne .noedd test cl,1 jz .noedd + + push 512 + sub sp, 14h + push 0 + push 1ah + mov si,sp + mov ah,48h ; EDD get drive parameters + mov dl,[ADVDrive] + push ds + push ss + pop ds + int 13h + pop ds + add sp,18h + pop ax + mov [ADVSsz], ax + mov si,.ebios .noedd: 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 +390,49 @@ adv_read_write: push si jmp si + extern xfer_buf_seg .ebios: 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,25 @@ 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 + cld + 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 +566,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 4d699f1..84f676c 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -729,7 +729,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 be1e13d..ce7fc5b 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -240,11 +240,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)) { @@ -287,7 +288,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) @@ -319,14 +321,18 @@ 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 || fs_type == XFS) { - 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; @@ -338,8 +344,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; @@ -501,7 +508,7 @@ error: return -1; } -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, *c32file; int fd = -1, dirfd = -1; diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index 9e1aef2..4d6dd6c 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -53,6 +53,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 14d8f8e..48305fa 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 */ @@ -164,6 +165,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 5e2188e..b6d372a 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -498,7 +498,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 66d53d2..52c64fd 100755 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -331,7 +331,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 9392d23..cddb8d6 100644 --- a/win/syslinux.c +++ b/win/syslinux.c @@ -488,7 +488,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.9.5