[syslinux] [PATCH 8/8] Fix ADV in adv.inc

Frediano Ziglio frediano.ziglio at citrix.com
Mon Sep 10 01:43:54 PDT 2012


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




More information about the Syslinux mailing list