VirtualBox

Changeset 89363 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
May 28, 2021 3:20:23 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144712
Message:

Devices/PC/BIOS/eltorito.c: Don't use the skip_b, skip_a mechanism for accessing arbitrary 512 byte sectors inside a 2048 byte CD sector for the emulation code but rather chop up the transfer into at most 3 separate ones to handle unaligned cases. This enables cleanups in the device drivers which comes next, bugref:4841

Location:
trunk/src/VBox/Devices/PC/BIOS
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/BIOS/ebda.h

    r89168 r89363  
    304304    uint16_t    sector_count;
    305305    chs_t       vdevice;        /* Virtual device geometry. */
     306    uint8_t __far *ptr_unaligned; /* Bounce buffer for sector unaligned reads. */
    306307} cdemu_t;
    307308#endif
  • trunk/src/VBox/Devices/PC/BIOS/eltorito.c

    r89168 r89363  
    7979#endif
    8080
     81#define MIN(a, b) ((a) < (b) ? (a) : (b))
    8182
    8283/// @todo put in a header
     
    153154extern  int     diskette_param_table;
    154155
     156/**
     157 * Allocates 2K of conventional memory.
     158 */
     159static uint16_t cdemu_bounce_buf_alloc(void)
     160{
     161    uint16_t    base_mem_kb;
     162    uint16_t    bounce_seg;
     163
     164    base_mem_kb = read_word(0x00, 0x0413);
     165    if (base_mem_kb == 0)
     166        return 0;
     167
     168    base_mem_kb -= 2;
     169    bounce_seg = (((uint32_t)base_mem_kb * 1024) >> 4); /* Calculate start segment. */
     170
     171    write_word(0x00, 0x0413, base_mem_kb);
     172
     173    return bounce_seg;
     174}
     175
    155176void BIOSCALL cdemu_init(void)
    156177{
    157178    /// @todo a macro or a function for getting the EBDA segment
    158179    uint16_t    ebda_seg = read_word(0x0040,0x000E);
     180    cdemu_t __far   *cdemu = ebda_seg :> &EbdaData->cdemu;
    159181
    160182    // the only important data is this one for now
    161     write_byte(ebda_seg,(uint16_t)&EbdaData->cdemu.active, 0x00);
     183    cdemu->active = 0x00;
     184    cdemu->ptr_unaligned = cdemu_bounce_buf_alloc() :> 0;
    162185}
    163186
     
    272295}
    273296
     297static uint16_t atapi_read(uint8_t device, uint32_t lba, uint16_t nbsectors, void __far *buf)
     298{
     299    uint16_t            ebda_seg=read_word(0x0040,0x000E);
     300    cdb_atapi           atapicmd;
     301    bio_dsk_t __far     *bios_dsk = ebda_seg :> &EbdaData->bdisk;
     302
     303    atapicmd.command = 0x28;    // READ 10 command
     304    atapicmd.lba     = swap_32(lba);
     305    atapicmd.nsect   = swap_16(nbsectors);
     306
     307    bios_dsk->drqp.nsect   = nbsectors;
     308    bios_dsk->drqp.sect_sz = 2048L;
     309    bios_dsk->drqp.skip_b  = 0;
     310    bios_dsk->drqp.skip_a  = 0;
     311
     312    return pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, nbsectors*2048L, ATA_DATA_IN, buf);
     313}
     314
     315static uint16_t cdemu_read(uint8_t device, uint32_t lba, uint16_t nbsectors, void __far *buf)
     316{
     317    uint16_t            ebda_seg=read_word(0x0040,0x000E);
     318    uint16_t            error;
     319    cdemu_t __far       *cdemu = ebda_seg :> &EbdaData->cdemu;
     320    uint32_t            ilba = cdemu->ilba;
     321    uint32_t            slba;
     322    uint16_t            before;
     323    uint8_t __far       *dst = (uint8_t __far *)buf;
     324
     325    BX_DEBUG_ELTORITO("cdemu_read: lba=%lu nbsectors=%u\n", lba, nbsectors);
     326
     327    // start lba on cd
     328    slba   = (uint32_t)lba / 4;
     329    before = (uint32_t)lba % 4;
     330
     331    // Unaligned start will go to a bounce buffer first.
     332    if (before)
     333    {
     334        uint16_t xfer_sect = MIN(nbsectors, 4 - before);
     335
     336        error = atapi_read(device, ilba + slba, 1, cdemu->ptr_unaligned);
     337        if (error != 0)
     338            return error;
     339
     340        _fmemcpy(dst, cdemu->ptr_unaligned + before * 512L, xfer_sect * 512L);
     341        dst       += xfer_sect * 512L;
     342        nbsectors -= xfer_sect;
     343        slba++;
     344    }
     345
     346    // Now for the aligned part.
     347    if (nbsectors / 4)
     348    {
     349        uint16_t xfer_sect = nbsectors / 4;
     350
     351        error = atapi_read(device, ilba + slba, xfer_sect, dst);
     352        if (error != 0)
     353            return error;
     354        dst       += xfer_sect * 2048L;
     355        nbsectors -= xfer_sect;
     356        slba      += xfer_sect;
     357    }
     358
     359    // Now for the unaligned end.
     360    if (nbsectors)
     361    {
     362        error = atapi_read(device, ilba + slba, 1, cdemu->ptr_unaligned);
     363        if (error != 0)
     364            return error;
     365
     366        _fmemcpy(dst, cdemu->ptr_unaligned, nbsectors * 512);
     367    }
     368
     369    return error;
     370}
     371
    274372// ---------------------------------------------------------------------------
    275373// End of ATA/ATAPI generic functions
     
    285383    uint16_t            ebda_seg=read_word(0x0040,0x000E);
    286384    uint8_t             buffer[2048];
    287     cdb_atapi           atapicmd;
    288385    uint32_t            lba;
    289386    uint16_t            boot_segment, nbsectors, i, error;
     
    307404
    308405    /* Read the Boot Record Volume Descriptor (BRVD). */
    309     _fmemset(&atapicmd, 0, sizeof(atapicmd));
    310     atapicmd.command = 0x28;    // READ 10 command
    311     atapicmd.lba     = swap_32(0x11);
    312     atapicmd.nsect   = swap_16(1);
    313 
    314     bios_dsk->drqp.nsect   = 1;
    315     bios_dsk->drqp.sect_sz = 2048;
    316 
    317406    for (read_try = 0; read_try <= 4; ++read_try)
    318407    {
    319         error = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, 2048L, ATA_DATA_IN, &buffer);
     408        error = atapi_read(device, 0x11, 1, &buffer);
    320409        if (!error)
    321410            break;
     
    341430
    342431    /* Now we read the Boot Catalog. */
    343     atapicmd.command = 0x28;    // READ 10 command
    344     atapicmd.lba     = swap_32(lba);
    345     atapicmd.nsect   = swap_16(1);
    346 
    347 #if 0   // Not necessary as long as previous values are reused
    348     bios_dsk->drqp.nsect   = 1;
    349     bios_dsk->drqp.sect_sz = 512;
    350 #endif
    351 
    352     error = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, 2048L, ATA_DATA_IN, &buffer);
     432    error = atapi_read(device, lba, 1, buffer);
    353433    if (error != 0)
    354434        return 7;
     
    407487
    408488    /* Read the disk image's boot sector into memory. */
    409     atapicmd.command = 0x28;    // READ 10 command
    410     atapicmd.lba     = swap_32(lba);
    411     atapicmd.nsect   = swap_16(1 + (nbsectors - 1) / 4);
    412 
    413     bios_dsk->drqp.nsect   = 1 + (nbsectors - 1) / 4;
    414     bios_dsk->drqp.sect_sz = 512;
    415 
    416     bios_dsk->drqp.skip_a = (2048 - nbsectors * 512) % 2048;
    417 
    418     error = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, nbsectors*512L, ATA_DATA_IN, MK_FP(boot_segment,0));
    419 
    420     bios_dsk->drqp.skip_a = 0;
    421 
     489    error = cdemu_read(device, 0, nbsectors, MK_FP(boot_segment,0));
    422490    if (error != 0)
    423491        return 13;
     
    482550    uint16_t            vheads, vspt, vcylinders;
    483551    uint16_t            head, sector, cylinder, nbsectors;
    484     uint32_t            vlba, ilba, slba, elba;
    485     uint16_t            before, segment, offset;
    486     cdb_atapi           atapicmd;
     552    uint32_t            vlba;
     553    uint16_t            segment, offset;
    487554    cdemu_t __far       *cdemu;
    488555    bio_dsk_t __far     *bios_dsk;
     
    554621        vcylinders = cdemu->vdevice.cylinders;
    555622        vheads     = cdemu->vdevice.heads;
    556         ilba       = cdemu->ilba;
    557623
    558624        sector    = GET_CL() & 0x003f;
     
    590656        SET_AL(nbsectors);
    591657
    592         // start lba on cd
    593         slba   = (uint32_t)vlba / 4;
    594         before = (uint32_t)vlba % 4;
    595 
    596         // end lba on cd
    597         elba = (uint32_t)(vlba + nbsectors - 1) / 4;
    598 
    599         _fmemset(&atapicmd, 0, sizeof(atapicmd));
    600         atapicmd.command = 0x28;    // READ 10 command
    601         atapicmd.lba     = swap_32(ilba + slba);
    602         atapicmd.nsect   = swap_16(elba - slba + 1);
    603 
    604         bios_dsk->drqp.nsect   = nbsectors;
    605         bios_dsk->drqp.sect_sz = 512;
    606 
    607         bios_dsk->drqp.skip_b = before * 512;
    608         bios_dsk->drqp.skip_a = ((4 - nbsectors % 4 - before) * 512) % 2048;
    609 
    610         status = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, before*512, nbsectors*512L, ATA_DATA_IN, MK_FP(segment,offset));
    611 
    612         bios_dsk->drqp.skip_b = 0;
    613         bios_dsk->drqp.skip_a = 0;
    614 
     658        status = cdemu_read(device, vlba, nbsectors, MK_FP(segment,offset));
    615659        if (status != 0) {
    616660            BX_INFO("%s: function %02x, error %02x !\n", __func__, GET_AH(), status);
     
    691735                          __func__, count, lba, segment, offset);
    692736
    693         nbsectors = count;
    694         vlba      = lba;
    695         ilba      = cdemu->ilba;
    696 
    697         // start lba on cd
    698         slba   = (uint32_t)vlba / 4;
    699         before = (uint32_t)vlba % 4;
    700 
    701         // end lba on cd
    702         elba = (uint32_t)(vlba + nbsectors - 1) / 4;
    703 
    704         _fmemset(&atapicmd, 0, sizeof(atapicmd));
    705         atapicmd.command = 0x28;    // READ 10 command
    706         atapicmd.lba     = swap_32(ilba + slba);
    707         atapicmd.nsect   = swap_16(elba - slba + 1);
    708 
    709         bios_dsk->drqp.skip_b = before * 512;
    710         bios_dsk->drqp.skip_a = ((4 - nbsectors % 4 - before) * 512) % 2048;
    711 
    712         status = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, before*512, nbsectors*512L, ATA_DATA_IN, MK_FP(segment,offset));
    713 
    714         bios_dsk->drqp.skip_b = 0;
    715         bios_dsk->drqp.skip_a = 0;
    716 
     737        status = cdemu_read(device, lba, count, MK_FP(segment,offset));
    717738        count = (uint16_t)(bios_dsk->drqp.trsfbytes >> 9);
    718739        i13x->count = count;
     
    774795    uint16_t            ebda_seg = read_word(0x0040,0x000E);
    775796    uint8_t             device, status, locks;
    776     cdb_atapi           atapicmd;
    777797    uint32_t            lba;
    778798    uint16_t            count, segment, offset;
     
    875895                          __func__, count, lba, segment, offset);
    876896
    877         _fmemset(&atapicmd, 0, sizeof(atapicmd));
    878         atapicmd.command = 0x28;    // READ 10 command
    879         atapicmd.lba     = swap_32(lba);
    880         atapicmd.nsect   = swap_16(count);
    881 
    882         bios_dsk->drqp.nsect   = count;
    883         bios_dsk->drqp.sect_sz = 2048;
    884 
    885         status = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, count*2048L, ATA_DATA_IN, MK_FP(segment,offset));
    886 
     897        status = atapi_read(device, lba, count, MK_FP(segment,offset));
    887898        count = (uint16_t)(bios_dsk->drqp.trsfbytes >> 11);
    888899        i13x->count = count;
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette