[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