📄 ide.c
字号:
ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); break; case WIN_READDMA_EXT: lba48 = 1; case WIN_READDMA: case WIN_READDMA_ONCE: if (!s->bs) goto abort_cmd; ide_cmd_lba48_transform(s, lba48); ide_sector_read_dma(s); break; case WIN_WRITEDMA_EXT: lba48 = 1; case WIN_WRITEDMA: case WIN_WRITEDMA_ONCE: if (!s->bs) goto abort_cmd; ide_cmd_lba48_transform(s, lba48); ide_sector_write_dma(s); break; case WIN_READ_NATIVE_MAX_EXT: lba48 = 1; case WIN_READ_NATIVE_MAX: ide_cmd_lba48_transform(s, lba48); ide_set_sector(s, s->nb_sectors - 1); s->status = READY_STAT; ide_set_irq(s); break; case WIN_CHECKPOWERMODE1: s->nsector = 0xff; /* device active or idle */ s->status = READY_STAT; ide_set_irq(s); break; case WIN_SETFEATURES: if (!s->bs) goto abort_cmd; /* XXX: valid for CDROM ? */ switch(s->feature) { case 0x02: /* write cache enable */ case 0x82: /* write cache disable */ case 0xaa: /* read look-ahead enable */ case 0x55: /* read look-ahead disable */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; case 0x03: { /* set transfer mode */ uint8_t val = s->nsector & 0x07; switch (s->nsector >> 3) { case 0x00: /* pio default */ case 0x01: /* pio mode */ put_le16(s->identify_data + 63,0x07); put_le16(s->identify_data + 88,0x3f); break; case 0x04: /* mdma mode */ put_le16(s->identify_data + 63,0x07 | (1 << (val + 8))); put_le16(s->identify_data + 88,0x3f); break; case 0x08: /* udma mode */ put_le16(s->identify_data + 63,0x07); put_le16(s->identify_data + 88,0x3f | (1 << (val + 8))); break; default: goto abort_cmd; } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; } default: goto abort_cmd; } break; case WIN_FLUSH_CACHE: case WIN_FLUSH_CACHE_EXT: case WIN_STANDBYNOW1: case WIN_IDLEIMMEDIATE: s->status = READY_STAT; ide_set_irq(s); break; /* ATAPI commands */ case WIN_PIDENTIFY: if (s->is_cdrom) { ide_atapi_identify(s); s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); } else { ide_abort_command(s); } ide_set_irq(s); break; case WIN_DIAGNOSE: ide_set_signature(s); s->status = 0x00; /* NOTE: READY is _not_ set */ s->error = 0x01; break; case WIN_SRST: if (!s->is_cdrom) goto abort_cmd; ide_set_signature(s); s->status = 0x00; /* NOTE: READY is _not_ set */ s->error = 0x01; break; case WIN_PACKETCMD: if (!s->is_cdrom) goto abort_cmd; /* overlapping commands not supported */ if (s->feature & 0x02) goto abort_cmd; s->atapi_dma = s->feature & 1; s->nsector = 1; ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, ide_atapi_cmd); break; default: abort_cmd: ide_abort_command(s); ide_set_irq(s); break; } }}static uint32_t ide_ioport_read(void *opaque, uint32_t addr1){ IDEState *ide_if = opaque; IDEState *s = ide_if->cur_drive; uint32_t addr; int ret, hob; addr = addr1 & 7; /* FIXME: HOB readback uses bit 7, but it's always set right now */ //hob = s->select & (1 << 7); hob = 0; switch(addr) { case 0: ret = 0xff; break; case 1: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else if (!hob) ret = s->error; else ret = s->hob_feature; break; case 2: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else if (!hob) ret = s->nsector & 0xff; else ret = s->hob_nsector; break; case 3: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else if (!hob) ret = s->sector; else ret = s->hob_sector; break; case 4: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else if (!hob) ret = s->lcyl; else ret = s->hob_lcyl; break; case 5: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else if (!hob) ret = s->hcyl; else ret = s->hob_hcyl; break; case 6: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else ret = s->select; break; default: case 7: if ((!ide_if[0].bs && !ide_if[1].bs) || (s != ide_if && !s->bs)) ret = 0; else ret = s->status; s->set_irq(s->irq_opaque, s->irq, 0); break; }#ifdef DEBUG_IDE printf("ide: read addr=0x%x val=%02x\n", addr1, ret);#endif return ret;}static uint32_t ide_status_read(void *opaque, uint32_t addr){ IDEState *ide_if = opaque; IDEState *s = ide_if->cur_drive; int ret; if ((!ide_if[0].bs && !ide_if[1].bs) || (s != ide_if && !s->bs)) ret = 0; else ret = s->status;#ifdef DEBUG_IDE printf("ide: read status addr=0x%x val=%02x\n", addr, ret);#endif return ret;}static void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val){ IDEState *ide_if = opaque; IDEState *s; int i;#ifdef DEBUG_IDE printf("ide: write control addr=0x%x val=%02x\n", addr, val);#endif /* common for both drives */ if (!(ide_if[0].cmd & IDE_CMD_RESET) && (val & IDE_CMD_RESET)) { /* reset low to high */ for(i = 0;i < 2; i++) { s = &ide_if[i]; s->status = BUSY_STAT | SEEK_STAT; s->error = 0x01; } } else if ((ide_if[0].cmd & IDE_CMD_RESET) && !(val & IDE_CMD_RESET)) { /* high to low */ for(i = 0;i < 2; i++) { s = &ide_if[i]; if (s->is_cdrom) s->status = 0x00; /* NOTE: READY is _not_ set */ else s->status = READY_STAT | SEEK_STAT; ide_set_signature(s); } } ide_if[0].cmd = val; ide_if[1].cmd = val;}static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val){ IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; p = s->data_ptr; *(uint16_t *)p = le16_to_cpu(val); p += 2; s->data_ptr = p; if (p >= s->data_end) s->end_transfer_func(s);}static uint32_t ide_data_readw(void *opaque, uint32_t addr){ IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; int ret; p = s->data_ptr; ret = cpu_to_le16(*(uint16_t *)p); p += 2; s->data_ptr = p; if (p >= s->data_end) s->end_transfer_func(s); return ret;}static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val){ IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; p = s->data_ptr; *(uint32_t *)p = le32_to_cpu(val); p += 4; s->data_ptr = p; if (p >= s->data_end) s->end_transfer_func(s);}static uint32_t ide_data_readl(void *opaque, uint32_t addr){ IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; int ret; p = s->data_ptr; ret = cpu_to_le32(*(uint32_t *)p); p += 4; s->data_ptr = p; if (p >= s->data_end) s->end_transfer_func(s); return ret;}static void ide_dummy_transfer_stop(IDEState *s){ s->data_ptr = s->io_buffer; s->data_end = s->io_buffer; s->io_buffer[0] = 0xff; s->io_buffer[1] = 0xff; s->io_buffer[2] = 0xff; s->io_buffer[3] = 0xff;}static void ide_reset(IDEState *s){ s->mult_sectors = MAX_MULT_SECTORS; s->cur_drive = s; s->select = 0xa0; s->status = READY_STAT; ide_set_signature(s); /* init the transfer handler so that 0xffff is returned on data accesses */ s->end_transfer_func = ide_dummy_transfer_stop; ide_dummy_transfer_stop(s);}struct partition { uint8_t boot_ind; /* 0x80 - active */ uint8_t head; /* starting head */ uint8_t sector; /* starting sector */ uint8_t cyl; /* starting cylinder */ uint8_t sys_ind; /* What partition type */ uint8_t end_head; /* end head */ uint8_t end_sector; /* end sector */ uint8_t end_cyl; /* end cylinder */ uint32_t start_sect; /* starting sector counting from 0 */ uint32_t nr_sects; /* nr of sectors in partition */} __attribute__((packed));/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */static int guess_disk_lchs(IDEState *s, int *pcylinders, int *pheads, int *psectors){ uint8_t buf[512]; int ret, i, heads, sectors, cylinders; struct partition *p; uint32_t nr_sects; ret = bdrv_read(s->bs, 0, buf, 1); if (ret < 0) return -1; /* test msdos magic */ if (buf[510] != 0x55 || buf[511] != 0xaa) return -1; for(i = 0; i < 4; i++) { p = ((struct partition *)(buf + 0x1be)) + i; nr_sects = le32_to_cpu(p->nr_sects); if (nr_sects && p->end_head) { /* We make the assumption that the partition terminates on a cylinder boundary */ heads = p->end_head + 1; sectors = p->end_sector & 63; if (sectors == 0) continue; cylinders = s->nb_sectors / (heads * sectors); if (cylinders < 1 || cylinders > 16383) continue; *pheads = heads; *psectors = sectors; *pcylinders = cylinders;#if 0 printf("guessed geometry: LCHS=%d %d %d\n", cylinders, heads, sectors);#endif return 0; } } return -1;}static void ide_init2(IDEState *ide_state, BlockDriverState *hd0, BlockDriverState *hd1, SetIRQFunc *set_irq, void *irq_opaque, int irq){ IDEState *s; static int drive_serial = 1; int i, cylinders, heads, secs, translation; int64_t nb_sectors; for(i = 0; i < 2; i++) { s = ide_state + i; if (i == 0) s->bs = hd0; else s->bs = hd1; if (s->bs) { bdrv_get_geometry(s->bs, &nb_sectors); s->nb_sectors = nb_sectors; /* if a geometry hint is available, use it */ bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); if (cylinders != 0) { s->cylinders = cylinders; s->heads = heads; s->sectors = secs; } else { if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) { if (heads > 16) { /* if heads > 16, it means that a BIOS LBA translation was active, so the default hardware geometry is OK */ goto default_geometry; } else { s->cylinders = cylinders; s->heads = heads; s->sectors = secs; /* disable any translation to be in sync with the logical geometry */ translation = bdrv_get_translation_hint(s->bs); if (translation == BIOS_ATA_TRANSLATION_AUTO) { bdrv_set_translation_hint(s->bs,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -