Beispiel #1
0
// Validate drive, find block size / sector count, and register drive.
int
scsi_init_drive(struct drive_s *drive, const char *s, int prio)
{
    struct disk_op_s dop;
    memset(&dop, 0, sizeof(dop));
    dop.drive_g = drive;
    struct cdbres_inquiry data;
    int ret = cdb_get_inquiry(&dop, &data);
    if (ret)
        return ret;
    char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1];
    char rev[sizeof(data.rev)+1];
    strtcpy(vendor, data.vendor, sizeof(vendor));
    nullTrailingSpace(vendor);
    strtcpy(product, data.product, sizeof(product));
    nullTrailingSpace(product);
    strtcpy(rev, data.rev, sizeof(rev));
    nullTrailingSpace(rev);
    int pdt = data.pdt & 0x1f;
    int removable = !!(data.removable & 0x80);
    dprintf(1, "%s vendor='%s' product='%s' rev='%s' type=%d removable=%d\n"
            , s, vendor, product, rev, pdt, removable);
    drive->removable = removable;

    if (pdt == SCSI_TYPE_CDROM) {
        drive->blksize = CDROM_SECTOR_SIZE;
        drive->sectors = (u64)-1;

        char *desc = znprintf(MAXDESCSIZE, "DVD/CD [%s Drive %s %s %s]"
                              , s, vendor, product, rev);
        boot_add_cd(drive, desc, prio);
        return 0;
    }

    ret = scsi_is_ready(&dop);
    if (ret) {
        dprintf(1, "scsi_is_ready returned %d\n", ret);
        return ret;
    }

    struct cdbres_read_capacity capdata;
    ret = cdb_read_capacity(&dop, &capdata);
    if (ret)
        return ret;

    // READ CAPACITY returns the address of the last block.
    // We do not bother with READ CAPACITY(16) because BIOS does not support
    // 64-bit LBA anyway.
    drive->blksize = be32_to_cpu(capdata.blksize);
    if (drive->blksize != DISK_SECTOR_SIZE) {
        dprintf(1, "%s: unsupported block size %d\n", s, drive->blksize);
        return -1;
    }
    drive->sectors = (u64)be32_to_cpu(capdata.sectors) + 1;
    dprintf(1, "%s blksize=%d sectors=%d\n"
            , s, drive->blksize, (unsigned)drive->sectors);

    // We do not recover from USB stalls, so try to be safe and avoid
    // sending the command if the (obsolete, but still provided by QEMU)
    // fixed disk geometry page may not be supported.
    //
    // We could also send the command only to small disks (e.g. <504MiB)
    // but some old USB keys only support a very small subset of SCSI which
    // does not even include the MODE SENSE command!
    //
    if (! CONFIG_COREBOOT && memcmp(vendor, "QEMU", 5) == 0) {
        struct cdbres_mode_sense_geom geomdata;
        ret = cdb_mode_sense_geom(&dop, &geomdata);
        if (ret == 0) {
            u32 cylinders;
            cylinders = geomdata.cyl[0] << 16;
            cylinders |= geomdata.cyl[1] << 8;
            cylinders |= geomdata.cyl[2];
            if (cylinders && geomdata.heads &&
                drive->sectors <= 0xFFFFFFFFULL &&
                ((u32)drive->sectors % (geomdata.heads * cylinders) == 0)) {
                drive->pchs.cylinders = cylinders;
                drive->pchs.heads = geomdata.heads;
                drive->pchs.spt = (u32)drive->sectors / (geomdata.heads * cylinders);
            }
        }
    }

    char *desc = znprintf(MAXDESCSIZE, "%s Drive %s %s %s"
                          , s, vendor, product, rev);
    boot_add_hd(drive, desc, prio);
    return 0;
}
Beispiel #2
0
int
cdrom_boot(struct drive_s *drive_g)
{
    ASSERT32FLAT();
    struct disk_op_s dop;
    int cdid = getDriveId(EXTTYPE_CD, drive_g);
    memset(&dop, 0, sizeof(dop));
    dop.drive_g = drive_g;
    if (!dop.drive_g || cdid < 0)
        return 1;

    int ret = scsi_is_ready(&dop);
    if (ret)
        dprintf(1, "scsi_is_ready returned %d\n", ret);

    // Read the Boot Record Volume Descriptor
    u8 buffer[CDROM_SECTOR_SIZE];
    dop.lba = 0x11;
    dop.count = 1;
    dop.buf_fl = buffer;
    ret = cdb_read(&dop);
    if (ret)
        return 3;

    // Validity checks
    if (buffer[0])
        return 4;
    if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
        return 5;

    // ok, now we calculate the Boot catalog address
    u32 lba = *(u32*)&buffer[0x47];

    // And we read the Boot Catalog
    dop.lba = lba;
    dop.count = 1;
    ret = cdb_read(&dop);
    if (ret)
        return 7;

    // Validation entry
    if (buffer[0x00] != 0x01)
        return 8;   // Header
    if (buffer[0x01] != 0x00)
        return 9;   // Platform
    if (buffer[0x1E] != 0x55)
        return 10;  // key 1
    if (buffer[0x1F] != 0xAA)
        return 10;  // key 2

    // Initial/Default Entry
    if (buffer[0x20] != 0x88)
        return 11; // Bootable

    u8 media = buffer[0x21];
    CDEmu.media = media;

    CDEmu.emulated_drive_gf = dop.drive_g;

    u16 boot_segment = *(u16*)&buffer[0x22];
    if (!boot_segment)
        boot_segment = 0x07C0;
    CDEmu.load_segment = boot_segment;
    CDEmu.buffer_segment = 0x0000;

    u16 nbsectors = *(u16*)&buffer[0x26];
    CDEmu.sector_count = nbsectors;

    lba = *(u32*)&buffer[0x28];
    CDEmu.ilba = lba;

    // And we read the image in memory
    dop.lba = lba;
    dop.count = DIV_ROUND_UP(nbsectors, 4);
    dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
    ret = cdb_read(&dop);
    if (ret)
        return 12;

    if (media == 0) {
        // No emulation requested - return success.
        CDEmu.emulated_extdrive = EXTSTART_CD + cdid;
        return 0;
    }

    // Emulation of a floppy/harddisk requested
    if (! CONFIG_CDROM_EMU || !cdemu_drive_gf)
        return 13;

    // Set emulated drive id and increase bios installed hardware
    // number of devices
    if (media < 4) {
        // Floppy emulation
        CDEmu.emulated_extdrive = 0x00;
        // XXX - get and set actual floppy count.
        set_equipment_flags(0x41, 0x41);

        switch (media) {
        case 0x01:  // 1.2M floppy
            CDEmu.lchs.spt = 15;
            CDEmu.lchs.cylinders = 80;
            CDEmu.lchs.heads = 2;
            break;
        case 0x02:  // 1.44M floppy
            CDEmu.lchs.spt = 18;
            CDEmu.lchs.cylinders = 80;
            CDEmu.lchs.heads = 2;
            break;
        case 0x03:  // 2.88M floppy
            CDEmu.lchs.spt = 36;
            CDEmu.lchs.cylinders = 80;
            CDEmu.lchs.heads = 2;
            break;
        }
    } else {
        // Harddrive emulation
        CDEmu.emulated_extdrive = 0x80;
        SET_BDA(hdcount, GET_BDA(hdcount) + 1);

        // Peak at partition table to get chs.
        struct mbr_s *mbr = (void*)0;
        u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl);
        u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
        u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);

        CDEmu.lchs.spt = sptcyl & 0x3f;
        CDEmu.lchs.cylinders = ((sptcyl<<2)&0x300) + cyllow + 1;
        CDEmu.lchs.heads = heads + 1;
    }

    // everything is ok, so from now on, the emulation is active
    CDEmu.active = 0x01;
    dprintf(6, "cdemu media=%d\n", media);

    return 0;
}