X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fide.c;h=f5baf953ac83cb6921bde6f20d3e0c2134d899d6;hb=c30d1b88a60c3a8df426ce81553675bbe4afef52;hp=4c0667719bfb9b407a603a48fde2f3cb0577287a;hpb=6c082361b3513b82d68f1eb41debc1e42ff0a8de;p=palacios.git diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c index 4c06677..f5baf95 100644 --- a/palacios/src/devices/ide.c +++ b/palacios/src/devices/ide.c @@ -26,7 +26,7 @@ #include "ide-types.h" #include "atapi-types.h" -#ifndef CONFIG_DEBUG_IDE +#ifndef V3_CONFIG_DEBUG_IDE #undef PrintDebug #define PrintDebug(fmt, args...) #endif @@ -110,16 +110,16 @@ struct ide_cd_state { }; struct ide_hd_state { - int accessed; + uint32_t accessed; /* this is the multiple sector transfer size as configured for read/write multiple sectors*/ - uint_t mult_sector_num; + uint32_t mult_sector_num; /* This is the current op sector size: * for multiple sector ops this equals mult_sector_num * for standard ops this equals 1 */ - uint_t cur_sector_num; + uint32_t cur_sector_num; }; struct ide_drive { @@ -137,11 +137,11 @@ struct ide_drive { char model[41]; // Where we are in the data transfer - uint_t transfer_index; + uint32_t transfer_index; // the length of a transfer // calculated for easy access - uint_t transfer_length; + uint32_t transfer_length; uint64_t current_lba; @@ -209,7 +209,7 @@ struct ide_channel { struct ide_dma_cmd_reg dma_cmd; struct ide_dma_status_reg dma_status; uint32_t dma_prd_addr; - uint_t dma_tbl_index; + uint32_t dma_tbl_index; }; @@ -356,7 +356,7 @@ static int dma_write(struct guest_info * core, struct ide_internal * ide, struct #include "ata.h" -#ifdef CONFIG_DEBUG_IDE +#ifdef V3_CONFIG_DEBUG_IDE static void print_prd_table(struct ide_internal * ide, struct ide_channel * channel) { struct ide_dma_prd prd_entry; int index = 0; @@ -375,7 +375,9 @@ static void print_prd_table(struct ide_internal * ide, struct ide_channel * chan } PrintDebug("\tPRD Addr: %x, PRD Len: %d, EOT: %d\n", - prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table); + prd_entry.base_addr, + (prd_entry.size == 0) ? 0x10000 : prd_entry.size, + prd_entry.end_of_table); if (prd_entry.end_of_table) { break; @@ -398,7 +400,7 @@ static int dma_read(struct guest_info * core, struct ide_internal * ide, struct // Read in the data buffer.... // Read a sector/block at a time until the prd entry is full. -#ifdef CONFIG_DEBUG_IDE +#ifdef V3_CONFIG_DEBUG_IDE print_prd_table(ide, channel); #endif @@ -425,7 +427,12 @@ static int dma_read(struct guest_info * core, struct ide_internal * ide, struct // loop through the PRD data.... - prd_bytes_left = prd_entry.size; + if (prd_entry.size == 0) { + // a size of 0 means 64k + prd_bytes_left = 0x10000; + } else { + prd_bytes_left = prd_entry.size; + } while (prd_bytes_left > 0) { @@ -448,11 +455,38 @@ static int dma_read(struct guest_info * core, struct ide_internal * ide, struct return -1; } } else { - PrintDebug("DMA of command packet\n"); - PrintError("How does this work???\n"); + /* + PrintError("DMA of command packet\n"); + PrintError("How does this work (ATAPI CMD=%x)???\n", drive->cd_state.atapi_cmd); return -1; + */ + int cmd_ret = 0; + bytes_to_write = (prd_bytes_left > bytes_left) ? bytes_left : prd_bytes_left; prd_bytes_left = bytes_to_write; + + cmd_ret = v3_write_gpa_memory(core, prd_entry.base_addr + prd_offset, + bytes_to_write, drive->data_buf); + + // check cmd_ret + + + bytes_to_write = 0; + prd_bytes_left = 0; + drive->transfer_index += bytes_to_write; + + channel->status.busy = 0; + channel->status.ready = 1; + channel->status.data_req = 0; + channel->status.error = 0; + channel->status.seek_complete = 1; + + channel->dma_status.active = 0; + channel->dma_status.err = 0; + + ide_raise_irq(ide, channel); + + return 0; } } @@ -1094,12 +1128,15 @@ static int read_hd_data(uint8_t * dst, uint_t length, struct ide_internal * ide, static int read_cd_data(uint8_t * dst, uint_t length, struct ide_internal * ide, struct ide_channel * channel) { struct ide_drive * drive = get_selected_drive(channel); int data_offset = drive->transfer_index % ATAPI_BLOCK_SIZE; - int req_offset = drive->transfer_index % drive->req_len; + // int req_offset = drive->transfer_index % drive->req_len; if (drive->cd_state.atapi_cmd != 0x28) { PrintDebug("IDE: Reading CD Data (len=%d) (req_len=%d)\n", length, drive->req_len); + PrintDebug("IDE: transfer len=%d, transfer idx=%d\n", drive->transfer_length, drive->transfer_index); } + + if (drive->transfer_index >= drive->transfer_length) { PrintError("Buffer Overrun... (xfer_len=%d) (cur_idx=%d) (post_idx=%d)\n", drive->transfer_length, drive->transfer_index, @@ -1121,7 +1158,7 @@ static int read_cd_data(uint8_t * dst, uint_t length, struct ide_internal * ide, // Should the req_offset be recalculated here????? - if ((req_offset == 0) && (drive->transfer_index > 0)) { + if (/*(req_offset == 0) &&*/ (drive->transfer_index > 0)) { if (drive->transfer_index < drive->transfer_length) { // An increment is complete, but there is still more data to be transferred... @@ -1136,6 +1173,8 @@ static int read_cd_data(uint8_t * dst, uint_t length, struct ide_internal * ide, } } else { // This was the final read of the request + + drive->req_len = 0; channel->status.data_req = 0; channel->status.ready = 1; @@ -1180,7 +1219,7 @@ static int ide_read_data_port(struct guest_info * core, ushort_t port, void * ds struct ide_channel * channel = get_selected_channel(ide, port); struct ide_drive * drive = get_selected_drive(channel); - PrintDebug("IDE: Reading Data Port %x (len=%d)\n", port, length); + // PrintDebug("IDE: Reading Data Port %x (len=%d)\n", port, length); if ((channel->cmd_reg == 0xec) || (channel->cmd_reg == 0xa1)) { @@ -1189,7 +1228,7 @@ static int ide_read_data_port(struct guest_info * core, ushort_t port, void * ds if (drive->drive_type == BLOCK_CDROM) { if (read_cd_data((uint8_t *)dst, length, ide, channel) == -1) { - PrintError("IDE: Could not read CD Data\n"); + PrintError("IDE: Could not read CD Data (atapi cmd=%x)\n", drive->cd_state.atapi_cmd); return -1; } } else if (drive->drive_type == BLOCK_DISK) { @@ -1275,6 +1314,15 @@ static int write_port_std(struct guest_info * core, ushort_t port, void * src, u PrintDebug("Attempting to select a non-present drive\n"); channel->error_reg.abort = 1; channel->status.error = 1; + } else { + channel->status.busy = 0; + channel->status.ready = 1; + channel->status.data_req = 0; + channel->status.error = 0; + channel->status.seek_complete = 1; + + channel->dma_status.active = 0; + channel->dma_status.err = 0; } break; @@ -1459,9 +1507,146 @@ static int ide_free(struct ide_internal * ide) { return 0; } +#ifdef V3_CONFIG_CHECKPOINT + +#include +static int ide_save(struct v3_chkpt_ctx * ctx, void * private_data) { + struct ide_internal * ide = (struct ide_internal *)private_data; + int ch_num = 0; + int drive_num = 0; + char buf[128]; + + + for (ch_num = 0; ch_num < 2; ch_num++) { + struct v3_chkpt_ctx * ch_ctx = NULL; + struct ide_channel * ch = &(ide->channels[ch_num]); + + snprintf(buf, 128, "channel-%d", ch_num); + ch_ctx = v3_chkpt_open_ctx(ctx->chkpt, ctx, buf); + + v3_chkpt_save_8(ch_ctx, "ERROR", &(ch->error_reg.val)); + v3_chkpt_save_8(ch_ctx, "FEATURES", &(ch->features.val)); + v3_chkpt_save_8(ch_ctx, "DRIVE_HEAD", &(ch->drive_head.val)); + v3_chkpt_save_8(ch_ctx, "STATUS", &(ch->status.val)); + v3_chkpt_save_8(ch_ctx, "CMD_REG", &(ch->cmd_reg)); + v3_chkpt_save_8(ch_ctx, "CTRL_REG", &(ch->ctrl_reg.val)); + v3_chkpt_save_8(ch_ctx, "DMA_CMD", &(ch->dma_cmd.val)); + v3_chkpt_save_8(ch_ctx, "DMA_STATUS", &(ch->dma_status.val)); + v3_chkpt_save_32(ch_ctx, "PRD_ADDR", &(ch->dma_prd_addr)); + v3_chkpt_save_32(ch_ctx, "DMA_TBL_IDX", &(ch->dma_tbl_index)); + + + for (drive_num = 0; drive_num < 2; drive_num++) { + struct v3_chkpt_ctx * drive_ctx = NULL; + struct ide_drive * drive = &(ch->drives[drive_num]); + + snprintf(buf, 128, "drive-%d-%d", ch_num, drive_num); + drive_ctx = v3_chkpt_open_ctx(ctx->chkpt, ch_ctx, buf); + + v3_chkpt_save_8(drive_ctx, "DRIVE_TYPE", &(drive->drive_type)); + v3_chkpt_save_8(drive_ctx, "SECTOR_COUNT", &(drive->sector_count)); + v3_chkpt_save_8(drive_ctx, "SECTOR_NUM", &(drive->sector_num)); + v3_chkpt_save_16(drive_ctx, "CYLINDER", &(drive->cylinder)); + + v3_chkpt_save_64(drive_ctx, "CURRENT_LBA", &(drive->current_lba)); + v3_chkpt_save_32(drive_ctx, "TRANSFER_LENGTH", &(drive->transfer_length)); + v3_chkpt_save_32(drive_ctx, "TRANSFER_INDEX", &(drive->transfer_index)); + + v3_chkpt_save(drive_ctx, "DATA_BUF", DATA_BUFFER_SIZE, drive->data_buf); + + + /* For now we'll just pack the type specific data at the end... */ + /* We should probably add a new context here in the future... */ + if (drive->drive_type == BLOCK_CDROM) { + v3_chkpt_save(drive_ctx, "ATAPI_SENSE_DATA", 18, drive->cd_state.sense.buf); + v3_chkpt_save_8(drive_ctx, "ATAPI_CMD", &(drive->cd_state.atapi_cmd)); + v3_chkpt_save(drive_ctx, "ATAPI_ERR_RECOVERY", 12, drive->cd_state.err_recovery.buf); + } else if (drive->drive_type == BLOCK_DISK) { + v3_chkpt_save_32(drive_ctx, "ACCESSED", &(drive->hd_state.accessed)); + v3_chkpt_save_32(drive_ctx, "MULT_SECT_NUM", &(drive->hd_state.mult_sector_num)); + v3_chkpt_save_32(drive_ctx, "CUR_SECT_NUM", &(drive->hd_state.cur_sector_num)); + } + } + } + + return 0; +} + + + +static int ide_load(struct v3_chkpt_ctx * ctx, void * private_data) { + struct ide_internal * ide = (struct ide_internal *)private_data; + int ch_num = 0; + int drive_num = 0; + char buf[128]; + + + for (ch_num = 0; ch_num < 2; ch_num++) { + struct v3_chkpt_ctx * ch_ctx = NULL; + struct ide_channel * ch = &(ide->channels[ch_num]); + + snprintf(buf, 128, "channel-%d", ch_num); + ch_ctx = v3_chkpt_open_ctx(ctx->chkpt, ctx, buf); + + v3_chkpt_load_8(ch_ctx, "ERROR", &(ch->error_reg.val)); + v3_chkpt_load_8(ch_ctx, "FEATURES", &(ch->features.val)); + v3_chkpt_load_8(ch_ctx, "DRIVE_HEAD", &(ch->drive_head.val)); + v3_chkpt_load_8(ch_ctx, "STATUS", &(ch->status.val)); + v3_chkpt_load_8(ch_ctx, "CMD_REG", &(ch->cmd_reg)); + v3_chkpt_load_8(ch_ctx, "CTRL_REG", &(ch->ctrl_reg.val)); + v3_chkpt_load_8(ch_ctx, "DMA_CMD", &(ch->dma_cmd.val)); + v3_chkpt_load_8(ch_ctx, "DMA_STATUS", &(ch->dma_status.val)); + v3_chkpt_load_32(ch_ctx, "PRD_ADDR", &(ch->dma_prd_addr)); + v3_chkpt_load_32(ch_ctx, "DMA_TBL_IDX", &(ch->dma_tbl_index)); + + + for (drive_num = 0; drive_num < 2; drive_num++) { + struct v3_chkpt_ctx * drive_ctx = NULL; + struct ide_drive * drive = &(ch->drives[drive_num]); + + snprintf(buf, 128, "drive-%d-%d", ch_num, drive_num); + drive_ctx = v3_chkpt_open_ctx(ctx->chkpt, ch_ctx, buf); + + v3_chkpt_load_8(drive_ctx, "DRIVE_TYPE", &(drive->drive_type)); + v3_chkpt_load_8(drive_ctx, "SECTOR_COUNT", &(drive->sector_count)); + v3_chkpt_load_8(drive_ctx, "SECTOR_NUM", &(drive->sector_num)); + v3_chkpt_load_16(drive_ctx, "CYLINDER", &(drive->cylinder)); + + v3_chkpt_load_64(drive_ctx, "CURRENT_LBA", &(drive->current_lba)); + v3_chkpt_load_32(drive_ctx, "TRANSFER_LENGTH", &(drive->transfer_length)); + v3_chkpt_load_32(drive_ctx, "TRANSFER_INDEX", &(drive->transfer_index)); + + v3_chkpt_load(drive_ctx, "DATA_BUF", DATA_BUFFER_SIZE, drive->data_buf); + + + /* For now we'll just pack the type specific data at the end... */ + /* We should probably add a new context here in the future... */ + if (drive->drive_type == BLOCK_CDROM) { + v3_chkpt_load(drive_ctx, "ATAPI_SENSE_DATA", 18, drive->cd_state.sense.buf); + v3_chkpt_load_8(drive_ctx, "ATAPI_CMD", &(drive->cd_state.atapi_cmd)); + v3_chkpt_load(drive_ctx, "ATAPI_ERR_RECOVERY", 12, drive->cd_state.err_recovery.buf); + } else if (drive->drive_type == BLOCK_DISK) { + v3_chkpt_load_32(drive_ctx, "ACCESSED", &(drive->hd_state.accessed)); + v3_chkpt_load_32(drive_ctx, "MULT_SECT_NUM", &(drive->hd_state.mult_sector_num)); + v3_chkpt_load_32(drive_ctx, "CUR_SECT_NUM", &(drive->hd_state.cur_sector_num)); + } + } + } + + return 0; +} + + + +#endif + static struct v3_device_ops dev_ops = { .free = (int (*)(void *))ide_free, +#ifdef V3_CONFIG_CHECKPOINT + .save = ide_save, + .load = ide_load +#endif }; @@ -1501,8 +1686,10 @@ static int connect_fn(struct v3_vm_info * vm, return -1; } - strncpy(drive->model, model_str, sizeof(drive->model) - 1); - + if (model_str != NULL) { + strncpy(drive->model, model_str, sizeof(drive->model) - 1); + } + if (strcasecmp(type_str, "cdrom") == 0) { drive->drive_type = BLOCK_CDROM;