2 #include "drv/disk/ata_dma.h"
7 #include "drv/disk/ata.h"
8 #include "debug/hexview.h"
11 #define ATA_PCI_VEN 0x8086
12 #define ATA_PCI_DEV 0x7010
14 #define ATA_DMA_READ 0xC8
15 #define ATA_DMA_WRITE 0xCA
21 uint16_t ata_dma_bar4;
23 prdt_t* ata_dma_prdt = 0;
24 size_t ata_dma_phys_prdt = 0;
25 size_t prdt_entry_count = 16;
31 pci_find_device(ATA_PCI_VEN, ATA_PCI_DEV, &ata_busnum, &ata_slot, &ata_func);
35 qemu_log(
"ATA DMA ID: %d (%x)", devnum, devnum);
37 if(devnum == PCI_VENDOR_NO_DEVICE) {
38 qemu_log(
"ATA DMA not found!");
41 qemu_log(
"Detected ATA DMA");
44 qemu_log(
"Enabling Busmastering");
47 command_register |= 0x05;
48 pci_write(ata_busnum, ata_slot, ata_func, 4, command_register);
50 qemu_log(
"Enabled Busmastering!!!");
54 if(ata_dma_bar4 & 0x01) {
55 ata_dma_bar4 &= 0xfffffffc;
58 qemu_log(
"ATA DMA: BAR4: %x (%d)", ata_dma_bar4, ata_dma_bar4);
60 qemu_log(
"PRDT: %d bytes",
sizeof(prdt_t));
63 ata_dma_prdt = kmalloc_common(
sizeof(prdt_t) * prdt_entry_count, PAGE_SIZE);
64 memset(ata_dma_prdt, 0,
sizeof(prdt_t) * prdt_entry_count);
66 ata_dma_phys_prdt = virt2phys(get_kernel_page_directory(), (virtual_addr_t) ata_dma_prdt);
68 qemu_log(
"PRDT ON: V%x; P%x", ata_dma_prdt, ata_dma_phys_prdt);
71 void ata_dma_clear_prdt() {
72 memset(ata_dma_prdt, 0,
sizeof(prdt_t) * prdt_entry_count);
75 void ata_dma_set_prdt_entry(prdt_t*
prdt, uint16_t index, uint32_t address, uint16_t byte_count,
bool is_last) {
76 prdt[index].buffer_phys = address;
77 prdt[index].transfer_size = byte_count;
78 prdt[index].mark_end = is_last ? ATA_DMA_MARK_END : 0;
81 void dump_prdt(prdt_t*
prdt) {
84 qemu_warn(
"Dumping PRDT:");
88 if(
prdt[i].transfer_size == 0)
91 size =
prdt[i].transfer_size;
93 qemu_log(
"[%d:%d] [Address: %x] -> %d", i,
prdt[i].mark_end,
prdt[i].buffer_phys, size);
97 }
while(
prdt[i - 1].mark_end != ATA_DMA_MARK_END);
99 qemu_ok(
"Entries: %d; Bytes to process: %d", i, bytes);
102 status_t ata_dma_read_sector(uint8_t drive, uint8_t *buf, uint32_t lba) {
104 qemu_err(
"Buffer is nullptr!");
105 return E_INVALID_BUFFER;
108 if (!drives[drive].online) {
109 qemu_err(
"Attempted read from drive that does not exist.");
110 return E_DEVICE_NOT_ONLINE;
114 ata_dma_clear_prdt();
117 void* temp_buf = kmalloc_common(PAGE_SIZE, PAGE_SIZE);
118 memset(temp_buf, 0, PAGE_SIZE);
121 size_t phys_buf = virt2phys(get_kernel_page_directory(), (virtual_addr_t) temp_buf);
124 ata_dma_set_prdt_entry(ata_dma_prdt, 0, phys_buf, 512,
true);
132 ata_set_params(drive, &io, &drive);
135 size_t status_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_STATUS : ATA_DMA_SECONDARY_STATUS;
136 size_t prdt_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_PRDT : ATA_DMA_SECONDARY_PRDT;
137 size_t cmd_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_CMD : ATA_DMA_SECONDARY_CMD;
139 outb(ata_dma_bar4 + cmd_offset, 8);
140 outb(ata_dma_bar4 + status_offset, 6);
143 outl(ata_dma_bar4 + prdt_offset, ata_dma_phys_prdt);
146 outb(io + ATA_REG_HDDEVSEL, drive == ATA_MASTER ? 0xE0 : 0xF0);
150 outb(io + ATA_REG_LBA0, (uint8_t)((lba) & 0xFF));
151 outb(io + ATA_REG_LBA1, (uint8_t)((lba >> 8) & 0xFF));
152 outb(io + ATA_REG_LBA2, (uint8_t)((lba >> 16) & 0xFF));
155 outb(io + ATA_REG_COMMAND, ATA_CMD_READ_DMA);
158 outb(ata_dma_bar4 + cmd_offset, 9);
161 int status = inb(ata_dma_bar4 + status_offset);
162 int dstatus = inb(io + ATA_REG_STATUS);
166 if (!(status & 0x04))
continue;
167 if (!(dstatus & 0x80))
break;
170 outb(ata_dma_bar4 + cmd_offset, 0);
172 memcpy(buf, temp_buf, 512);
182 status_t ata_dma_read_sectors(uint8_t drive, uint8_t *buf, uint32_t lba, uint8_t numsects) {
184 qemu_err(
"Buffer is nullptr!");
185 return E_INVALID_BUFFER;
188 if (!drives[drive].online) {
189 qemu_err(
"Attempted read from drive that does not exist.");
190 return E_DEVICE_NOT_ONLINE;
195 ata_dma_clear_prdt();
198 size_t phys_buf = virt2phys(get_kernel_page_directory(), (virtual_addr_t)buf);
206 byte_count = 256 * 512;
208 byte_count = numsects * 512;
212 while(byte_count >= 65536) {
215 ata_dma_set_prdt_entry(ata_dma_prdt, i, phys_buf + (i * 65536), 0,
false);
221 if(byte_count != 0) {
223 ata_dma_set_prdt_entry(ata_dma_prdt, i, phys_buf + (i * 65536), byte_count,
true);
226 ata_dma_prdt[i - 1].mark_end = ATA_DMA_MARK_END;
237 ata_set_params(drive, &io, &drive);
240 size_t status_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_STATUS : ATA_DMA_SECONDARY_STATUS;
241 size_t prdt_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_PRDT : ATA_DMA_SECONDARY_PRDT;
242 size_t cmd_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_CMD : ATA_DMA_SECONDARY_CMD;
244 outb(ata_dma_bar4 + cmd_offset, 8);
245 outb(ata_dma_bar4 + status_offset, 6);
248 outl(ata_dma_bar4 + prdt_offset, ata_dma_phys_prdt);
251 outb(io + ATA_REG_HDDEVSEL, drive == ATA_MASTER ? 0xE0 : 0xF0);
255 outb(io + ATA_REG_SECCOUNT0, numsects);
256 outb(io + ATA_REG_LBA0, lba & 0xFF);
257 outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF);
258 outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF);
261 outb(io + ATA_REG_COMMAND, ATA_CMD_READ_DMA);
266 outb(ata_dma_bar4 + cmd_offset, 9);
269 int status = inb(ata_dma_bar4 + status_offset);
270 int dstatus = inb(io + ATA_REG_STATUS);
274 if (!(status & 0x04))
continue;
275 if (!(dstatus & 0x80))
break;
278 outb(ata_dma_bar4 + cmd_offset, 0);
291 status_t ata_dma_write_sectors(uint8_t drive, uint8_t *buf, uint32_t lba, uint8_t numsects) {
293 qemu_err(
"Buffer is nullptr!");
294 return E_INVALID_BUFFER;
297 if (!drives[drive].online) {
298 qemu_err(
"Attempted read from drive that does not exist.");
299 return E_DEVICE_NOT_ONLINE;
303 ata_dma_clear_prdt();
306 size_t phys_buf = virt2phys(get_kernel_page_directory(), (virtual_addr_t)buf);
314 byte_count = 256 * 512;
316 byte_count = numsects * 512;
320 while(byte_count >= 65536) {
323 ata_dma_set_prdt_entry(ata_dma_prdt, i, phys_buf + (i * 65536), 0,
false);
329 if(byte_count != 0) {
331 ata_dma_set_prdt_entry(ata_dma_prdt, i, phys_buf + (i * 65536), byte_count,
true);
334 ata_dma_prdt[i - 1].mark_end = ATA_DMA_MARK_END;
345 ata_set_params(drive, &io, &drive);
348 size_t status_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_STATUS : ATA_DMA_SECONDARY_STATUS;
349 size_t prdt_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_PRDT : ATA_DMA_SECONDARY_PRDT;
350 size_t cmd_offset = io == ATA_PRIMARY_IO ? ATA_DMA_PRIMARY_CMD : ATA_DMA_SECONDARY_CMD;
352 outb(ata_dma_bar4 + cmd_offset, 0);
353 outb(ata_dma_bar4 + status_offset, 6);
356 outl(ata_dma_bar4 + prdt_offset, ata_dma_phys_prdt);
359 outb(io + ATA_REG_HDDEVSEL, drive == ATA_MASTER ? 0xE0 : 0xF0);
363 outb(io + ATA_REG_SECCOUNT0, numsects);
364 outb(io + ATA_REG_LBA0, lba & 0xFF);
365 outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF);
366 outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF);
369 outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_DMA);
374 outb(ata_dma_bar4 + cmd_offset, 1);
377 int status = inb(ata_dma_bar4 + status_offset);
378 int dstatus = inb(io + ATA_REG_STATUS);
380 qemu_log(
"Status: %x; Dstatus: %x; ERR: %d", status, dstatus, status & (1 << 1));
382 if (!(status & 0x04))
continue;
383 if (!(dstatus & 0x80))
break;
386 outb(ata_dma_bar4 + cmd_offset, 0);
391 status_t ata_dma_read(uint8_t drive,
char *buf, uint32_t location, uint32_t length) {
393 qemu_err(
"Buffer is nullptr!");
394 return E_INVALID_BUFFER;
397 if(!drives[drive].online) {
398 qemu_err(
"Attempted read from drive that does not exist.");
399 return E_DEVICE_NOT_ONLINE;
402 qemu_log(
"DRIVE: %d; Buffer: %x, Location: %x, len: %d", drive, buf, location, length);
404 size_t start_sector = location / drives[drive].
block_size;
405 size_t end_sector = (location + length - 1) / drives[drive].block_size;
406 size_t sector_count = end_sector - start_sector + 1;
408 size_t real_length = sector_count * drives[drive].
block_size;
411 uint8_t* real_buf = kmalloc_common(real_length, PAGE_SIZE);
413 if(!drives[drive].is_packet) {
416 size_t cluster_count = sector_count / 256;
417 size_t remaining_count = sector_count % 256;
419 for(; i < cluster_count; i++) {
420 ata_dma_read_sectors(drive, real_buf + (i * (65536 * 2)), start_sector + (i * 256), 0);
423 if(remaining_count != 0)
424 ata_dma_read_sectors(drive, real_buf + (i * (65536 * 2)), start_sector + (i * 256), remaining_count);
429 memcpy(buf, real_buf + (location % drives[drive].block_size), length);
436 status_t ata_dma_write(uint8_t drive,
const char *buf, uint32_t location, uint32_t length) {
438 qemu_err(
"Buffer is nullptr!");
439 return E_INVALID_BUFFER;
442 if(!drives[drive].online) {
443 qemu_log(
"Attempted read from drive that does not exist.");
444 return E_DEVICE_NOT_ONLINE;
447 size_t start_sector = location / drives[drive].
block_size;
448 size_t end_sector = (location + length - 1) / drives[drive].block_size;
449 size_t sector_count = end_sector - start_sector + 1;
451 size_t real_length = sector_count * drives[drive].
block_size;
454 uint8_t* real_buf = kmalloc_common(real_length, PAGE_SIZE);
456 ata_dma_read_sectors(drive, real_buf, start_sector, sector_count);
458 size_t start_offset = location % drives[drive].
block_size;
459 memcpy(real_buf + start_offset, buf, length);
461 if(!drives[drive].is_packet) {
464 size_t cluster_count = sector_count / 256;
465 size_t remaining_count = sector_count % 256;
467 for(; i < cluster_count; i++) {
468 ata_dma_write_sectors(drive, real_buf + (i * (65536 * 2)), start_sector + (i * 256), 0);
471 if(remaining_count != 0)
472 ata_dma_write_sectors(drive, real_buf + (i * (65536 * 2)), start_sector + (i * 256), remaining_count);
Основные определения ядра
void * memset(void *ptr, char value, size_t num)
Заполнение массива указанными символами
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
uint16_t pci_read_confspc_word(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
[PCI] Чтение 16-битных полей из пространства механизма конфигураций 1
void pci_find_device(uint16_t vendor, uint16_t device, uint8_t *bus_ret, uint8_t *slot_ret, uint8_t *func_ret)
[PCI] Поиск устройства по ID-поставшика и устройства
uint16_t pci_get_device(uint8_t bus, uint8_t slot, uint8_t function)
[PCI] Получение ID-Устройства
Эта структура определяет каждый ATA диск в системе
uint16_t block_size
Адресация по CHS?