diff options
author | H. Peter Anvin <hpa@zytor.com> | 2010-05-12 21:23:13 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-05-12 21:23:13 -0700 |
commit | ae197a98b905a7da7872eef29dcbb0f822fa81de (patch) | |
tree | 8749bdaf86105d27506361cb673212e1ae2bc946 /core | |
parent | c6bebc44627afe5a652d4e305527ca12e90ff768 (diff) | |
download | syslinux-ae197a98b905a7da7872eef29dcbb0f822fa81de.tar.gz |
diskio: make maxtransfer per-device, cap to 127, imported from headsyslinux-4.00-pre43
Make the maxtransfer per device, as it should be; properly imported
from the head loader (in case it is patched with -s). Also enforce
capping to 127 for EBIOS and 63 for CBIOS. This is structured so that
once EDD4 is approved we can remove the capping for that particular
subcase.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'core')
-rw-r--r-- | core/diskstart.inc | 2 | ||||
-rw-r--r-- | core/fs/diskio.c | 42 | ||||
-rw-r--r-- | core/fs/fs.c | 3 | ||||
-rw-r--r-- | core/include/disk.h | 6 | ||||
-rw-r--r-- | core/isolinux.asm | 8 | ||||
-rw-r--r-- | core/pxelinux.asm | 1 |
6 files changed, 40 insertions, 22 deletions
diff --git a/core/diskstart.inc b/core/diskstart.inc index c24b64ab..14384774 100644 --- a/core/diskstart.inc +++ b/core/diskstart.inc @@ -456,7 +456,6 @@ bailmsg: db 'Boot error', 0Dh, 0Ah, 0 zb 1F8h-($-$$) FirstSector dd 0xDEADBEEF ; Location of sector 1 - global MaxTransfer MaxTransfer dw 0x007F ; Max transfer size ; This field will be filled in 0xAA55 by the installer, but we abuse it @@ -746,5 +745,6 @@ expand_super: xor ebx,ebx mov si,[bsHeads] mov di,[bsSecPerTrack] + movzx ebp,word [MaxTransfer] pm_call fs_init popad diff --git a/core/fs/diskio.c b/core/fs/diskio.c index cdbed793..d2f1671d 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -1,3 +1,4 @@ +#include <dprintf.h> #include <stdio.h> #include <string.h> #include <stdbool.h> @@ -8,8 +9,6 @@ #define RETRY_COUNT 6 -static uint16_t MaxTransfer = 1 << (16 - 9); - static int chs_rdwr_sectors(struct disk *disk, void *buf, sector_t lba, size_t count, bool is_write) { @@ -32,8 +31,8 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf, while (count) { chunk = count; - if (chunk > MaxTransfer) - chunk = MaxTransfer; + if (chunk > disk->maxtransfer) + chunk = disk->maxtransfer; freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift; @@ -77,7 +76,7 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf, /* For any starting value, this will always end with ..., 1, 0 */ chunk >>= 1; if (chunk) { - MaxTransfer = chunk; + disk->maxtransfer = chunk; retry = RETRY_COUNT; ireg.eax.b[0] = chunk; continue; @@ -129,8 +128,8 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, lba += disk->part_start; while (count) { chunk = count; - if (chunk > MaxTransfer) - chunk = MaxTransfer; + if (chunk > disk->maxtransfer) + chunk = disk->maxtransfer; freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift; @@ -150,14 +149,14 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, if (tptr != ptr && is_write) memcpy(tptr, ptr, bytes); - pkt.size = sizeof pkt; - pkt.blocks = chunk; - pkt.buf = FAR_PTR(tptr); - pkt.lba = lba; - retry = RETRY_COUNT; for (;;) { + pkt.size = sizeof pkt; + pkt.blocks = chunk; + pkt.buf = FAR_PTR(tptr); + pkt.lba = lba; + __intcall(0x13, &ireg, &oreg); if (!(oreg.eflags.l & EFLAGS_CF)) break; @@ -167,9 +166,8 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, /* For any starting value, this will always end with ..., 1, 0 */ chunk >>= 1; if (chunk) { - MaxTransfer = chunk; + disk->maxtransfer = chunk; retry = RETRY_COUNT; - pkt.blocks = chunk; continue; } @@ -237,13 +235,15 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, - uint16_t bsHeads, uint16_t bsSecPerTrack) + uint16_t bsHeads, uint16_t bsSecPerTrack, + uint32_t MaxTransfer) { static struct disk disk; static __lowmem struct edd_disk_params edd_params; com32sys_t ireg, oreg; bool ebios = cdrom; int sector_size = cdrom ? 2048 : 512; + unsigned int hard_max_transfer = ebios ? 127 : 63; memset(&ireg, 0, sizeof ireg); @@ -258,6 +258,7 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, if (cdrom || (!(oreg.eflags.l & EFLAGS_CF) && oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1))) { ebios = true; + hard_max_transfer = 127; /* Query EBIOS parameters */ edd_params.len = sizeof edd_params; @@ -300,6 +301,11 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, disk.part_start = part_start; disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; + if (!MaxTransfer || MaxTransfer > hard_max_transfer) + MaxTransfer = hard_max_transfer; + + disk.maxtransfer = MaxTransfer; + return &disk; } @@ -310,12 +316,14 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, * NOTE: the disk cache needs to be revamped to support multiple devices... */ struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start, - uint16_t bsHeads, uint16_t bsSecPerTrack) + uint16_t bsHeads, uint16_t bsSecPerTrack, + uint32_t MaxTransfer) { static struct device dev; static __hugebss char diskcache[128*1024]; - dev.disk = disk_init(devno, cdrom, part_start, bsHeads, bsSecPerTrack); + dev.disk = disk_init(devno, cdrom, part_start, + bsHeads, bsSecPerTrack, MaxTransfer); dev.cache_data = diskcache; dev.cache_size = sizeof diskcache; diff --git a/core/fs/fs.c b/core/fs/fs.c index 6ea74bf8..792da02f 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -363,6 +363,7 @@ void fs_init(com32sys_t *regs) sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32); uint16_t disk_heads = regs->esi.w[0]; uint16_t disk_sectors = regs->edi.w[0]; + uint32_t maxtransfer = regs->ebp.l; int blk_shift = -1; struct device *dev = NULL; /* ops is a ptr list for several fs_ops */ @@ -387,7 +388,7 @@ void fs_init(com32sys_t *regs) } else { if (!dev) dev = device_init(disk_devno, disk_cdrom, disk_offset, - disk_heads, disk_sectors); + disk_heads, disk_sectors, maxtransfer); fs.fs_dev = dev; } /* invoke the fs-specific init code */ diff --git a/core/include/disk.h b/core/include/disk.h index da6555ae..df0476a3 100644 --- a/core/include/disk.h +++ b/core/include/disk.h @@ -23,6 +23,8 @@ struct disk { sector_t part_start; /* the start address of this partition(in sectors) */ + uint32_t maxtransfer; /* Max sectors per transfer */ + int (*rdwr_sectors)(struct disk *, void *, sector_t, size_t, bool); }; @@ -30,7 +32,7 @@ extern void read_sectors(char *, sector_t, int); extern void getoneblk(struct disk *, char *, block_t, int); /* diskio.c */ -struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t); -struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t); +struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t); +struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t); #endif /* DISK_H */ diff --git a/core/isolinux.asm b/core/isolinux.asm index d1d5bf8d..d2ba81d9 100644 --- a/core/isolinux.asm +++ b/core/isolinux.asm @@ -1093,7 +1093,6 @@ bios_ebios: dw getlinsec_ebios, bios_ebios_str %endif ; Maximum transfer size - global MaxTransfer MaxTransfer dw 127 ; Hard disk modes MaxTransferCD dw 32 ; CD mode @@ -1154,11 +1153,18 @@ all_read: ; (which will be at 16 only for a single-session disk!); from the PVD ; we should be able to find the rest of what we need to know. ; +init_fs: pushad mov eax,ROOT_FS_OPS mov dl,[DriveNumber] cmp word [BIOSType],bios_cdrom sete dh ; 1 for cdrom, 0 for hybrid mode + jne .hybrid + movzx ebp,word [MaxTransferCD] + jmp .common +.hybrid: + movzx ebp,word [MaxTransfer] +.common: mov ecx,[bsHidden] mov ebx,[bsHidden+4] mov si,[bsHeads] diff --git a/core/pxelinux.asm b/core/pxelinux.asm index 2e7e6075..204b09c8 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -221,6 +221,7 @@ adhcp_copy: ; do fs initialize ; mov eax,ROOT_FS_OPS + xor ebp,ebp pm_call fs_init section .rodata |