X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fata.h;fp=palacios%2Fsrc%2Fdevices%2Fata.h;h=b759f0bfc2205a4c4d491d7ce1220ef149ddffcb;hb=6661dd1d2aa547ae248e816dcd4201bcbcb7fee0;hp=0000000000000000000000000000000000000000;hpb=4659d019e2f65b9397e2289a9add28a3adf47cf8;p=palacios.git diff --git a/palacios/src/devices/ata.h b/palacios/src/devices/ata.h new file mode 100644 index 0000000..b759f0b --- /dev/null +++ b/palacios/src/devices/ata.h @@ -0,0 +1,192 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Jack Lange + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + + +static void ata_identify_device(struct ide_drive * drive) { + struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf); + const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0"; + const char* firmware = "ALPHA1 "; + + drive->transfer_length = 512; + drive->transfer_index = 0; + + + memset(drive_id->buf, 0, sizeof(drive_id->buf)); + + drive_id->fixed_drive = 1; + drive_id->removable_media = 0; + + // Black magic... + drive_id->disk_speed1 = 1; + drive_id->disk_speed3 = 1; + + drive_id->cdrom_flag = 0; + + // Make it the simplest drive possible (1 head, 1 cyl, 1 sect/track) + drive_id->num_cylinders = 1; + drive_id->num_heads = 1; + drive_id->bytes_per_track = IDE_SECTOR_SIZE; + drive_id->bytes_per_sector = IDE_SECTOR_SIZE; + drive_id->sectors_per_track = 1; + + + // These buffers do not contain a terminating "\0" + memcpy(drive_id->serial_num, serial_number, strlen(serial_number)); + memcpy(drive_id->firmware_rev, firmware, strlen(firmware)); + memcpy(drive_id->model_num, drive->model, 40); + + // 32 bits access + drive_id->dword_io = 1; + + // enable DMA access + drive_id->dma_enable = 1; + + // enable LBA access + drive_id->lba_enable = 1; + + // Drive Capacity (28 bit LBA) + drive_id->lba_capacity = drive->hd_ops->get_capacity(drive->private_data); + + // Drive Capacity (48 bit LBA) + drive_id->lba_capacity_2 = drive->hd_ops->get_capacity(drive->private_data); + + drive_id->rw_multiples = 0x80ff; + + // words 64-70, 54-58 valid + drive_id->field_valid = 0x0007; // DMA + pkg cmd valid + + // copied from CFA540A + drive_id->buf[63] = 0x0103; // variable (DMA stuff) + //drive_id->buf[63] = 0x0000; // variable (DMA stuff) + + // drive_id->buf[64] = 0x0001; // PIO + drive_id->buf[65] = 0x00b4; + drive_id->buf[66] = 0x00b4; + drive_id->buf[67] = 0x012c; + drive_id->buf[68] = 0x00b4; + + drive_id->buf[71] = 30; // faked + drive_id->buf[72] = 30; // faked + + // drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4 + drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6 + + drive_id->buf[83] |= 0x0400; // supports 48 bit LBA + + + drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported; +} + + +static int ata_read(struct vm_device * dev, struct ide_channel * channel) { + struct ide_drive * drive = get_selected_drive(channel); + + if (drive->hd_state.accessed == 0) { + drive->current_lba = 0; + drive->hd_state.accessed = 1; + } + + int ret = drive->hd_ops->read(drive->data_buf, 1, drive->current_lba, drive->private_data); + + if (ret == -1) { + PrintError("IDE: Error reading HD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba)); + return -1; + } + + return 0; +} + + + +// 28 bit LBA +static int ata_read_sectors(struct vm_device * dev, struct ide_channel * channel) { + struct ide_drive * drive = get_selected_drive(channel); + // The if the sector count == 0 then read 256 sectors (cast up to handle that value) + uint32_t sect_cnt = (drive->sector_count == 0) ? 256 : drive->sector_count; + + union { + uint32_t addr; + uint8_t buf[4]; + } __attribute__((packed)) lba_addr; + + /* LBA addr bits: + 0-8: sector number reg (drive->lba0) + 8-16: low cylinder reg (drive->lba1) + 16-24: high cylinder reg (drive->lba2) + 24-28: low 4 bits of drive_head reg (channel->drive_head.head_num) + */ + + lba_addr.buf[0] = drive->lba0; + lba_addr.buf[1] = drive->lba1; + lba_addr.buf[2] = drive->lba2; + lba_addr.buf[3] = channel->drive_head.lba3; + + PrintDebug("LBA Address %d\n", drive->lba0); + PrintDebug("sector_num %d\n", drive->sector_num); + + + if (lba_addr.addr + (sect_cnt * IDE_SECTOR_SIZE) > + drive->hd_ops->get_capacity(drive->private_data)) { + PrintError("IDE: request size exceeds disk capacity (lba=%d) (sect_cnt=%d) (ReadEnd=%d) (capacity=%p)\n", + lba_addr.addr, sect_cnt, + lba_addr.addr + (sect_cnt * IDE_SECTOR_SIZE), + (void *)(addr_t)(drive->hd_ops->get_capacity(drive->private_data))); + ide_abort_command(dev, channel); + return 0; + } + + drive->current_lba = lba_addr.addr; + + if (ata_read(dev, channel) == -1) { + PrintError("Could not read disk sector\n"); + return -1; + } + + drive->transfer_length = sect_cnt * IDE_SECTOR_SIZE; + drive->transfer_index = 0; + + channel->status.busy = 0; + channel->status.ready = 0; + channel->status.write_fault = 0; + channel->status.data_req = 1; + channel->status.error = 0; + + drive->irq_flags.io_dir = 1; + drive->irq_flags.c_d = 0; + drive->irq_flags.rel = 0; + + + ide_raise_irq(dev, channel); + + PrintDebug("Returning from read sectors\n"); + + return 0; +} + + +// 48 bit LBA +static int ata_read_sectors_ext(struct vm_device * dev, struct ide_channel * channel) { + //struct ide_drive * drive = get_selected_drive(channel); + // The if the sector count == 0 then read 256 sectors (cast up to handle that value) + //uint32_t sector_count = (drive->sector_count == 0) ? 256 : drive->sector_count; + + PrintError("Extended Sector read not implemented\n"); + + return -1; +}