1 #include "drv/disk/ata.h"
6 #include "drv/disk/dpm.h"
8 #include "net/endianess.h"
9 #include "drv/disk/ata_dma.h"
10 #include "drv/disk/ata_pio.h"
11 #include "drv/disk/mbr.h"
12 #include "debug/hexview.h"
16 #define DEFAULT_TIMEOUT (65535 * 2)
18 const char possible_dpm_letters_for_ata[4] =
"CDEF";
21 bool ide_poll_drq(uint16_t io) {
23 uint8_t status = inb(io + ATA_REG_STATUS);
24 if(status & ATA_SR_DRQ) {
26 }
else if ((status & ATA_SR_ERR) || (status & ATA_SR_DF)) {
32 bool ide_poll_bsy(uint16_t io) {
34 uint8_t status = inb(io + ATA_REG_STATUS);
35 if(!(status & ATA_SR_BSY)) {
37 }
else if ((status & ATA_SR_ERR) || (status & ATA_SR_DF)) {
43 void ide_select_drive(uint8_t bus,
bool slave) {
44 if(bus == ATA_PRIMARY)
45 outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, (0xA0 | ((uint8_t)slave << 4)));
47 outb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, (0xA0 | ((uint8_t)slave << 4)));
54 inb(ATA_PRIMARY_IO + ATA_REG_STATUS);
63 inb(ATA_SECONDARY_IO + ATA_REG_STATUS);
68 void ide_soft_reset(
size_t io) {
69 outb(io + ATA_REG_CONTROL, 0x04);
71 outb(io + ATA_REG_CONTROL, 0);
74 size_t dpm_ata_read(
size_t Disk, uint64_t high_offset, uint64_t low_offset,
size_t Size,
void* Buffer){
76 DPM_Disk dpm = dpm_info(Disk + 65);
80 ata_read((uint8_t) dpm.Point, Buffer, low_offset, Size);
85 size_t dpm_ata_write(
size_t Disk, uint64_t high_offset, uint64_t low_offset,
size_t Size,
void* Buffer){
87 DPM_Disk dpm = dpm_info(Disk + 65);
91 ata_write((uint8_t) dpm.Point, Buffer, low_offset, Size);
96 uint8_t ide_identify(uint8_t bus, uint8_t drive) {
97 uint16_t io = (bus == ATA_PRIMARY) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO;
99 uint8_t drive_num = (bus << 1) | drive;
101 qemu_log(
"Identifying %s %s", PRIM_SEC(bus), MAST_SLV(drive));
104 ide_select_drive(bus, drive);
106 outb(io + ATA_REG_SECCOUNT0, 0);
107 outb(io + ATA_REG_LBA0, 0);
108 outb(io + ATA_REG_LBA1, 0);
109 outb(io + ATA_REG_LBA2, 0);
111 outb(io + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
112 qemu_log(
"Sent IDENTIFY");
114 uint8_t status = inb(io + ATA_REG_STATUS);
116 qemu_log(
"Status: %d; Err: %d", status, status & ATA_SR_ERR);
118 size_t timeout = DEFAULT_TIMEOUT;
120 uint16_t *ide_buf = kcalloc(512, 1);
125 uint8_t seccount = inb(io + ATA_REG_SECCOUNT0);
126 uint8_t lba_l = inb(io + ATA_REG_LBA0);
127 uint8_t lba_m = inb(io + ATA_REG_LBA1);
128 uint8_t lba_h = inb(io + ATA_REG_LBA2);
130 qemu_warn(
"%x %x %x %x", seccount, lba_l, lba_m, lba_h);
134 if(seccount == 0x01 && lba_l == 0x01 && lba_m == 0x14 && lba_h == 0xEB) {
137 qemu_log(
"ATA Packet Device!");
139 drives[drive_num].online =
true;
142 outb(io + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
144 for(
int i = 0; i < 256; i++) {
145 *(uint16_t *)(ide_buf + i) = inw(io + ATA_REG_DATA);
148 uint16_t* fwver = kcalloc(8, 1);
149 uint16_t* model_name = kcalloc(40, 1);
150 uint16_t* serial = kcalloc(20, 1);
152 memcpy(serial, ide_buf + 10, 20);
153 memcpy(fwver, ide_buf + 23, 8);
154 memcpy(model_name, ide_buf + 27, 40);
156 for(
int i = 0; i < 10; i++) {
157 serial[i] = bit_flip_short(serial[i]);
160 for(
int i = 0; i < 4; i++) {
161 fwver[i] = bit_flip_short(fwver[i]);
164 for(
int i = 0; i < 20; i++) {
165 model_name[i] = bit_flip_short(model_name[i]);
169 ((uint8_t*)serial)[19] = 0;
170 ((uint8_t*)fwver)[7] = 0;
171 ((uint8_t*)model_name)[39] = 0;
176 drives[drive_num].
capacity = atapi_read_size(bus, drive);
177 drives[drive_num].
block_size = atapi_read_block_size(bus, drive);
179 drives[drive_num].fwversion = (
char *) fwver;
180 drives[drive_num].
model_name = (
char *) model_name;
181 drives[drive_num].serial_number = (
char *) serial;
183 qemu_log(
"Size is: %d", drives[drive_num].capacity);
185 qemu_note(
"DRIVE: %d", drive_num);
187 qemu_note(
"Serial: %s", serial);
188 qemu_note(
"Firmware version: %s", fwver);
189 qemu_note(
"Model name: %s", model_name);
193 possible_dpm_letters_for_ata[drive_num],
197 drives[drive_num].capacity * drives[drive_num].block_size,
198 drives[drive_num].capacity,
199 drives[drive_num].block_size,
206 qemu_err(
"[ATA] [DPM] [ERROR] An error occurred during disk registration, error code: %d",disk_inx);
208 qemu_ok(
"[ATA] [DPM] [Successful] [is_packet: %d] Your disk index: %d",drives[drive_num].is_packet, disk_inx);
209 dpm_fnc_write(disk_inx + 65, &dpm_ata_read, &dpm_ata_write);
215 }
else if(seccount == 0x7F && lba_l == 0x7F && lba_m == 0x7F && lba_h == 0x7F) {
216 qemu_err(
"Error possible (Virtualbox returns 0x7f 0x7f 0x7f 0x7f for non-existent drives)");
222 while((status & ATA_SR_BSY) != 0){
223 qemu_log(
"Got status %x", status);
224 if(status & ATA_SR_ERR) {
225 qemu_log(
"%s %s has ERR set. Disabled.", PRIM_SEC(bus), MAST_SLV(drive));
231 qemu_log(
"ATA Timeout expired!");
238 status = inb(io + ATA_REG_STATUS);
241 timeout = DEFAULT_TIMEOUT;
243 while(!(status & ATA_SR_DRQ)) {
244 qemu_log(
"Got status %x", status);
245 if(status & ATA_SR_ERR) {
246 qemu_log(
"%s %s has ERR set. Disabled.", PRIM_SEC(bus), MAST_SLV(drive));
252 qemu_log(
"ATA Timeout expired!");
259 status = inb(io + ATA_REG_STATUS);
262 drives[drive_num].online =
true;
264 qemu_log(
"%s %s is online.", PRIM_SEC(bus), MAST_SLV(drive));
266 for(
int i = 0; i < 256; i++) {
267 *(uint16_t *)(ide_buf + i) = inw(io + ATA_REG_DATA);
271 drives[drive_num].fwversion = kcalloc(8, 1);
272 drives[drive_num].
model_name = kcalloc(40, 1);
273 drives[drive_num].serial_number = kcalloc(20, 1);
275 uint16_t* fwver = (uint16_t *) drives[drive_num].fwversion;
276 uint16_t* model_name = (uint16_t *) drives[drive_num].model_name;
277 uint16_t* serial = (uint16_t *) drives[drive_num].serial_number;
279 memcpy(serial, ide_buf + 10, 20);
280 memcpy(fwver, ide_buf + 23, 8);
281 memcpy(model_name, ide_buf + 27, 40);
283 for(
int i = 0; i < 10; i++) {
284 serial[i] = bit_flip_short(serial[i]);
287 for(
int i = 0; i < 4; i++) {
288 fwver[i] = bit_flip_short(fwver[i]);
291 for(
int i = 0; i < 20; i++) {
292 model_name[i] = bit_flip_short(model_name[i]);
296 ((uint8_t*)serial)[19] = 0;
297 ((uint8_t*)fwver)[7] = 0;
298 ((uint8_t*)model_name)[39] = 0;
301 size_t capacity = (ide_buf[101] << 16) | ide_buf[100];
303 qemu_log(
"CAP: %u", capacity);
305 drives[drive_num].drive = drive_num;
307 drives[drive_num].
capacity = capacity;
308 drives[drive_num].
is_dma = (ide_buf[49] & 0x200) ?
true :
false;
312 possible_dpm_letters_for_ata[drive_num],
318 drives[drive_num].block_size,
325 qemu_err(
"[ATA] [DPM] [ERROR] An error occurred during disk registration, error code: %d",disk_inx);
327 qemu_ok(
"[ATA] [DPM] [Successful] [is_packet: %d] Your disk index: %d",drives[drive_num].is_packet, disk_inx);
328 dpm_fnc_write(possible_dpm_letters_for_ata[drive_num], &dpm_ata_read, &dpm_ata_write);
332 qemu_log(
"Identify finished");
334 qemu_err(
"%s %s => No status. Drive may be disconnected!", PRIM_SEC(bus), MAST_SLV(drive));
344 void ide_400ns_delay(uint16_t io) {
345 inb(io + ATA_REG_ALTSTATUS);
346 inb(io + ATA_REG_ALTSTATUS);
347 inb(io + ATA_REG_ALTSTATUS);
348 inb(io + ATA_REG_ALTSTATUS);
351 void ide_poll(uint16_t io) {
354 uint8_t status
__attribute__((unused)) = inb(io + ATA_REG_STATUS);
357 status = inb(io + ATA_REG_STATUS);
359 if(!(status & ATA_SR_BSY))
364 status = inb(io + ATA_REG_STATUS);
365 if(status & ATA_SR_ERR) {
366 qemu_err(
"ERR set, device failure!\n");
370 if(status & ATA_SR_DRQ)
376 void ata_read(uint8_t drive, uint8_t* buf, uint32_t location, uint32_t length) {
378 qemu_log(
"Buffer is nullptr!");
382 if(!drives[drive].online) {
383 qemu_log(
"Attempted read from drive that does not exist.");
387 if((!drives[drive].is_packet) && drives[drive].is_dma) {
388 ata_dma_read(drive, (
char*)buf, location, length);
392 size_t start_sector = location / drives[drive].
block_size;
393 size_t end_sector = (location + length - 1) / drives[drive].block_size;
394 size_t sector_count = end_sector - start_sector + 1;
396 size_t real_length = sector_count * drives[drive].
block_size;
400 uint8_t* real_buf = kmalloc(real_length);
403 if(!drives[drive].is_packet) {
404 ata_pio_read_sectors(drive, real_buf, start_sector, sector_count);
406 atapi_read_sectors(drive, real_buf, start_sector, sector_count);
409 memcpy(buf, real_buf + (location % drives[drive].block_size), length);
414 void ata_write(uint8_t drive,
const uint8_t* buf,
size_t location,
size_t length) {
416 qemu_log(
"Buffer is nullptr!");
420 if(!drives[drive].online) {
421 qemu_log(
"Attempted read from drive that does not exist.");
425 size_t start_sector = location / drives[drive].
block_size;
426 size_t end_sector = (location + length - 1) / drives[drive].block_size;
427 size_t sector_count = end_sector - start_sector + 1;
429 uint8_t* temp_buf = kmalloc(sector_count * drives[drive].block_size);
431 ata_pio_read_sectors(drive, temp_buf, start_sector, sector_count);
433 size_t start_offset = location % drives[drive].
block_size;
434 memcpy(temp_buf + start_offset, buf, length);
436 ata_pio_write_sectors(drive, temp_buf, start_sector, sector_count);
442 for (
size_t i = 0; i < 4; i++) {
443 _tty_printf(
"\tATA: %s %s: %s ",
444 PRIM_SEC((i >> 1) & 1),
446 drives[i].online?
"online ":
"offline"
449 if(!drives[i].online) {
454 _tty_printf(
"%u sectors = ", drives[i].capacity);
458 if(drives[i].is_packet) {
459 megabytes = (drives[i].
capacity * 2048) >> 20;
461 megabytes = (drives[i].
capacity >> 5) / (1 << 6);
464 _tty_printf(
"%u MB = %u GB", megabytes, megabytes >> 10);
466 if(drives[i].is_packet)
467 _tty_printf(
" [PACKET DEVICE!!!]");
469 if(drives[i].is_sata)
470 _tty_printf(
" [SATA]");
473 _tty_printf(
" [DMA]");
475 qemu_note(
"Drive %d", i);
476 qemu_note(
"'%s' '%s' '%s'", drives[i].model_name, drives[i].fwversion, drives[i].serial_number);
478 _tty_printf(
"\n\t|-- Model: \"%s\"; Firmware version: \"%s\";", drives[i].model_name, drives[i].fwversion);
479 _tty_printf(
"\n\t|-- Serial number: \"%s\";", drives[i].serial_number);
487 void ata_check_all() {
488 ide_identify(ATA_PRIMARY, ATA_MASTER);
489 ide_identify(ATA_PRIMARY, ATA_SLAVE);
490 ide_identify(ATA_SECONDARY, ATA_MASTER);
491 ide_identify(ATA_SECONDARY, ATA_SLAVE);
495 qemu_log(
"Checking for ATA drives");
497 register_interrupt_handler(32 + ATA_PRIMARY_IRQ, ide_primary_irq);
498 register_interrupt_handler(32 + ATA_SECONDARY_IRQ, ide_secondary_irq);
struct registers __attribute__((packed))
Структура данных пакета от мыши
int dpm_reg(char Letter, char *Name, char *FS, int Status, size_t Size, size_t Sectors, size_t SectorSize, int AddrMode, char *Serial, void *Point)
[DPM] Регистрация дискового раздела
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Эта структура определяет каждый ATA диск в системе
bool is_dma
Является ли этот диск SATA устройством?
char * model_name
Поддерживает ли этот диск DMA?
uint16_t block_size
Адресация по CHS?
size_t capacity
Устройство доступно?
bool is_packet
Ёмкость диска в секторах