diskio: make maxtransfer per-device, cap to 127, imported from head syslinux-4.00-pre43
authorH. Peter Anvin <hpa@zytor.com>
Thu, 13 May 2010 04:23:13 +0000 (21:23 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 13 May 2010 04:23:13 +0000 (21:23 -0700)
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>
core/diskstart.inc
core/fs/diskio.c
core/fs/fs.c
core/include/disk.h
core/isolinux.asm
core/pxelinux.asm

index c24b64a..1438477 100644 (file)
@@ -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
index cdbed79..d2f1671 100644 (file)
@@ -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;
index 6ea74bf..792da02 100644 (file)
@@ -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 */
index da6555a..df0476a 100644 (file)
@@ -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 */
index d1d5bf8..d2ba81d 100644 (file)
@@ -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]
index 2e7e607..204b09c 100644 (file)
@@ -221,6 +221,7 @@ adhcp_copy:
 ; do fs initialize
 ;
                mov eax,ROOT_FS_OPS
+               xor ebp,ebp
                 pm_call fs_init
 
                section .rodata