[syslinux] [PATCH 3/3] 4k_sector: Fix ADV in adv.inc

Frediano Ziglio frediano.ziglio at citrix.com
Wed Feb 13 08:51:52 PST 2013


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



More information about the Syslinux mailing list