summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-05-12 21:23:13 -0700
committerH. Peter Anvin <hpa@zytor.com>2010-05-12 21:23:13 -0700
commitae197a98b905a7da7872eef29dcbb0f822fa81de (patch)
tree8749bdaf86105d27506361cb673212e1ae2bc946
parentc6bebc44627afe5a652d4e305527ca12e90ff768 (diff)
downloadsyslinux-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>
-rw-r--r--core/diskstart.inc2
-rw-r--r--core/fs/diskio.c42
-rw-r--r--core/fs/fs.c3
-rw-r--r--core/include/disk.h6
-rw-r--r--core/isolinux.asm8
-rw-r--r--core/pxelinux.asm1
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