From: Jack Lange Date: Fri, 10 Apr 2009 01:02:58 +0000 (-0500) Subject: cdrom DMA functional X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=e89fcf9ca3b902f647593a816b750551ac3840ca cdrom DMA functional --- diff --git a/palacios/src/devices/atapi.h b/palacios/src/devices/atapi.h index acc90ff..ec613d7 100644 --- a/palacios/src/devices/atapi.h +++ b/palacios/src/devices/atapi.h @@ -191,15 +191,25 @@ static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) { drive->current_lba = lba; // Update the request length value in the cylinder registers - + drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE; + drive->transfer_index = 0; + + if (channel->features.dma) { + + if (channel->dma_status.active == 1) { + if (dma_read(dev, channel) == -1) { + PrintError("Error in DMA read for CD Read10 command\n"); + return -1; + } + } + return 0; + } + if (atapi_read_chunk(dev, channel) == -1) { PrintError("IDE: Could not read initial chunk from CD\n"); return -1; } - drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE; - drive->transfer_index = 0; - // Length of ATAPI buffer sits in cylinder registers // This is weird... The host sets this value to say what it would like to transfer, // if it is larger than the correct size, the device shrinks it to the correct size diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c index f9695de..4acc679 100644 --- a/palacios/src/devices/ide.c +++ b/palacios/src/devices/ide.c @@ -354,7 +354,7 @@ static void ide_abort_command(struct vm_device * dev, struct ide_channel * chann } - +static int dma_read(struct vm_device * dev, struct ide_channel * channel); @@ -371,78 +371,99 @@ static int dma_read(struct vm_device * dev, struct ide_channel * channel) { struct ide_drive * drive = get_selected_drive(channel); // This is at top level scope to do the EOT test at the end struct ide_dma_prd prd_entry; + uint_t bytes_left = drive->transfer_length; // Read in the data buffer.... // Read a sector/block at a time until the prd entry is full. - if (drive->drive_type == IDE_DISK) { - uint_t bytes_left = drive->transfer_length; - // Loop through the disk data - while (bytes_left > 0) { + PrintDebug("DMA read for %d bytes\n", bytes_left); - uint32_t prd_entry_addr = channel->dma_prd_addr + (sizeof(struct ide_dma_prd) * channel->dma_tbl_index); - uint_t prd_bytes_left = 0; - uint_t prd_offset = 0; - int ret; - - PrintDebug("PRD table address = %x\n", channel->dma_prd_addr); - - ret = read_guest_pa_memory(dev->vm, prd_entry_addr, sizeof(struct ide_dma_prd), (void *)&prd_entry); - - if (ret != sizeof(struct ide_dma_prd)) { - PrintError("Could not read PRD\n"); - return -1; - } - - PrintDebug("PRD Addr: %x, PDR Len: %d, EOT: %d\n", prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table); + // Loop through the disk data + while (bytes_left > 0) { + + uint32_t prd_entry_addr = channel->dma_prd_addr + (sizeof(struct ide_dma_prd) * channel->dma_tbl_index); + uint_t prd_bytes_left = 0; + uint_t prd_offset = 0; + int ret; - // loop through the PRD data.... + PrintDebug("PRD table address = %x\n", channel->dma_prd_addr); + + ret = read_guest_pa_memory(dev->vm, prd_entry_addr, sizeof(struct ide_dma_prd), (void *)&prd_entry); + + if (ret != sizeof(struct ide_dma_prd)) { + PrintError("Could not read PRD\n"); + return -1; + } + + PrintDebug("PRD Addr: %x, PDR Len: %d, EOT: %d\n", prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table); + + // loop through the PRD data.... + + prd_bytes_left = prd_entry.size; + + + while (prd_bytes_left > 0) { + uint_t bytes_to_write = 0; - prd_bytes_left = prd_entry.size; - - - while (prd_bytes_left > 0) { - uint_t bytes_to_write = (prd_bytes_left > IDE_SECTOR_SIZE) ? IDE_SECTOR_SIZE : prd_bytes_left; - - + if (drive->drive_type == IDE_DISK) { + bytes_to_write = (prd_bytes_left > IDE_SECTOR_SIZE) ? IDE_SECTOR_SIZE : prd_bytes_left; + + if (ata_read(dev, channel, drive->data_buf, 1) == -1) { PrintError("Failed to read next disk sector\n"); return -1; } - - drive->current_lba++; - - ret = write_guest_pa_memory(dev->vm, prd_entry.base_addr + prd_offset, bytes_to_write, drive->data_buf); + } else if (drive->drive_type == IDE_CDROM) { + bytes_to_write = (prd_bytes_left > ATAPI_BLOCK_SIZE) ? ATAPI_BLOCK_SIZE : prd_bytes_left; - if (ret != bytes_to_write) { - PrintError("Failed to copy data into guest memory... (ret=%d)\n", ret); + if (atapi_read_chunk(dev, channel) == -1) { + PrintError("Failed to read next disk sector\n"); return -1; } - - drive->transfer_index += ret; - prd_bytes_left -= ret; - prd_offset += ret; - bytes_left -= ret; } - channel->dma_tbl_index++; + PrintDebug("Writing DMA data to guest Memory ptr=%p, len=%d\n", + (void *)(addr_t)(prd_entry.base_addr + prd_offset), bytes_to_write); + + drive->current_lba++; + + ret = write_guest_pa_memory(dev->vm, prd_entry.base_addr + prd_offset, bytes_to_write, drive->data_buf); + + if (ret != bytes_to_write) { + PrintError("Failed to copy data into guest memory... (ret=%d)\n", ret); + return -1; + } + + PrintDebug("\t DMA ret=%d, (prd_bytes_left=%d) (bytes_left=%d)\n", ret, prd_bytes_left, bytes_left); + + drive->transfer_index += ret; + prd_bytes_left -= ret; + prd_offset += ret; + bytes_left -= ret; + } + + channel->dma_tbl_index++; + + if (drive->drive_type == IDE_DISK) { if (drive->transfer_index % IDE_SECTOR_SIZE) { PrintError("We currently don't handle sectors that span PRD descriptors\n"); return -1; } - - if ((prd_entry.end_of_table == 1) && (bytes_left > 0)) { - PrintError("DMA table not large enough for data transfer...\n"); + } else if (drive->drive_type == IDE_CDROM) { + if (drive->transfer_index % ATAPI_BLOCK_SIZE) { + PrintError("We currently don't handle ATAPI BLOCKS that span PRD descriptors\n"); return -1; } - } - - } else if (drive->drive_type == IDE_CDROM) { - PrintError("CDROM DMA not supported\n"); - return -1; + + + if ((prd_entry.end_of_table == 1) && (bytes_left > 0)) { + PrintError("DMA table not large enough for data transfer...\n"); + return -1; + } + } /* @@ -733,6 +754,23 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de } break; } + + + case 0xe0: // Standby Now 1 + case 0xe1: // Set Idle Immediate + case 0xe2: // Standby + case 0xe3: // Set Idle 1 + case 0xe6: // Sleep Now 1 + case 0x94: // Standby Now 2 + case 0x95: // Idle Immediate (CFA) + case 0x96: // Standby 2 + case 0x97: // Set idle 2 + case 0x99: // Sleep Now 2 + channel->status.val = 0; + channel->status.ready = 1; + ide_raise_irq(dev, channel); + break; + case 0xef: // Set Features // Prior to this the features register has been written to. // This command tells the drive to check if the new value is supported (the value is drive specific) @@ -910,6 +948,15 @@ static int read_cd_data(uint8_t * dst, uint_t length, struct vm_device * dev, st return -1; } + { + static uint32_t read_cnt = 0; + + if ((read_cnt % 200) == 0) { + PrintError("CD data port read %d\n", read_cnt); + } + + read_cnt++; + } if ((data_offset == 0) && (drive->transfer_index > 0)) {