1 #include "drv/disk/ahci.h"
11 #include "drv/disk/ata.h"
12 #include "drv/atapi.h"
13 #include "net/endianess.h"
14 #include "drv/disk/dpm.h"
18 #define AHCI_SUBCLASS 6
22 uint8_t ahci_busnum, ahci_slot, ahci_func;
23 uint16_t ahci_vendor = 0, ahci_devid = 0;
25 bool ahci_initialized =
false;
27 volatile AHCI_HBA_MEM* abar;
38 #define AHCI_PORT(num) (abar->ports + (num))
42 void ahci_irq_handler();
47 pci_find_device_by_class_and_subclass(AHCI_CLASS, AHCI_SUBCLASS, &ahci_vendor, &ahci_devid, &ahci_busnum, &ahci_slot, &ahci_func);
50 if(ahci_vendor == 0 || ahci_devid == 0) {
51 qemu_err(
"AHCI contoller not found!");
56 qemu_ok(
"Found VEN: %x DEV: %x", ahci_vendor, ahci_devid);
59 pci_enable_bus_mastering(ahci_busnum, ahci_slot, ahci_func);
65 abar = (
volatile AHCI_HBA_MEM*)(
pci_read32(ahci_busnum, ahci_slot, ahci_func, 0x24) & ~0b1111U);
67 qemu_log(
"AHCI ABAR is: %p", abar);
71 get_kernel_page_directory(),
72 (physical_addr_t) abar,
73 (virtual_addr_t) abar,
75 PAGE_WRITEABLE | PAGE_CACHE_DISABLE
78 qemu_log(
"Version: %x", abar->version);
80 if(abar->host_capabilities_extended & 1U) {
81 for(
int i = 0; i < 5; i++) {
82 qemu_warn(
"PERFORMING BIOS HANDOFF!!!");
85 abar->handoff_control_and_status = abar->handoff_control_and_status | (1 << 1);
88 size_t status = abar->handoff_control_and_status;
90 if (~status & (1 << 0)) {
95 qemu_ok(
"No BIOS Handoff");
99 abar->global_host_control = (1 << 31) ;
109 qemu_log(
"AHCI IRQ: %x (%d)", ahci_irq, ahci_irq);
111 register_interrupt_handler(32 + ahci_irq, ahci_irq_handler);
114 abar->global_host_control |= (1 << 0);
116 while((abar->global_host_control & 1) == 1)
119 tty_printf(
"Reset okay");
121 abar->global_host_control |= (1 << 31) | (1 << 1);
123 qemu_ok(
"Enabled AHCI and INTERRUPTS");
125 size_t caps = abar->capability;
126 size_t slotCount = ((caps >> 8) & 0x1f) + 1;
128 qemu_log(
"Slot count: %d", slotCount);
130 size_t maxports = (caps & 0x1f) + 1;
132 qemu_log(
"Max port count: %d", maxports);
136 uint32_t implemented_ports = abar->port_implemented;
138 qemu_log(
"PI is: %x", implemented_ports);
140 for(uint32_t i = 0; i < 32; i++) {
141 if (implemented_ports & (1 << i)) {
142 AHCI_HBA_PORT* port = AHCI_PORT(i);
146 if((port->command_and_status & (1 << 2)) != (1 << 2)) {
147 port->command_and_status |= (1 << 2);
152 if((port->command_and_status & (1 << 1)) != (1 << 1)) {
153 port->sata_error = 0xFFFFFFFF;
155 port->sata_control = 0;
157 port->command_and_status |= (1 << 1);
162 if (!ahci_is_drive_attached(i)) {
166 port->sata_error = 0xFFFFFFFF;
169 port->command_and_status = port->command_and_status & 0xfffffffe;
171 while(port->command_and_status & (1 << 15))
174 tty_printf(
"[%d] AFTER CMD = %x\n", i, port->command_and_status);
176 ahci_rebase_memory_for(i);
180 for(
int i = 0; i < 32; i++) {
181 if(abar->port_implemented & (1 << i)) {
182 volatile AHCI_HBA_PORT* port = abar->ports + i;
184 qemu_log(
"[%p: Port %d]", port, i);
186 if(!ahci_is_drive_attached(i)) {
187 qemu_log(
"\tNo drive attached to port!");
191 if(port->signature == AHCI_SIGNATURE_SATAPI) {
192 qemu_log(
"\tSATAPI drive");
193 ahci_identify(i,
true);
195 }
else if(port->signature == AHCI_SIGNATURE_SATA) {
196 qemu_log(
"\tSATA drive");
197 ahci_identify(i,
false);
199 qemu_log(
"Other device: %x", port->signature);
204 ahci_initialized =
true;
207 void ahci_rebase_memory_for(
size_t port_num) {
211 ahci_stop_cmd(port_num);
214 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
216 void* virt = kmalloc_common(MEMORY_PER_AHCI_PORT, PAGE_SIZE);
217 memset(virt, 0, MEMORY_PER_AHCI_PORT);
220 phys_set_flags(get_kernel_page_directory(), (virtual_addr_t) virt, PAGE_WRITEABLE | PAGE_CACHE_DISABLE);
222 size_t phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) virt);
224 ports[port_num].command_list_addr_virt = virt;
225 ports[port_num].command_list_addr_phys = phys;
227 ports[port_num].fis_virt = AHCI_FIS(virt, 0);
228 ports[port_num].fis_phys = AHCI_FIS(phys, 0);
232 port->command_list_base_address_low = phys;
233 port->command_list_base_address_high = 0;
235 port->fis_base_address_low = AHCI_FIS(phys, 0);
236 port->fis_base_address_high = 0;
240 for(
int i = 0; i < 32; i++) {
241 cmdheader[i].prdtl = COMMAND_TABLE_PRDT_ENTRY_COUNT;
243 cmdheader[i].ctba = AHCI_COMMAND_TABLE_ENTRY(phys, 0, i);
245 cmdheader[i].ctbau = 0;
253 ahci_start_cmd(port_num);
255 qemu_ok(
"Rebasing memory for: %d is OK.", port_num);
258 bool ahci_is_drive_attached(
size_t port_num) {
263 uint32_t implemented_ports = abar->port_implemented;
265 if(implemented_ports & (1 << port_num)) {
266 volatile AHCI_HBA_PORT* port = abar->ports + port_num;
268 uint32_t status = port->sata_status;
270 uint8_t ipm = (status >> 8) & 0xF;
271 uint8_t det = status & 0xF;
273 if(ipm == 1 && det == 3) {
281 int ahci_free_cmd_slot(
size_t port_num) {
285 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
287 uint32_t slots = port->sata_active | port->command_issue;
289 for(
int i = 0; i < 32; i++) {
290 if((slots & (1 << i)) == 0)
297 void ahci_start_cmd(
size_t port_num) {
301 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
303 while (port->command_and_status & AHCI_HBA_CR);
305 port->command_and_status |= AHCI_HBA_FRE;
306 port->command_and_status |= AHCI_HBA_ST;
309 void ahci_stop_cmd(
size_t port_num) {
313 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
315 port->command_and_status &= ~AHCI_HBA_ST;
316 port->command_and_status &= ~AHCI_HBA_FRE;
319 if (port->command_and_status & AHCI_HBA_FR)
321 if (port->command_and_status & AHCI_HBA_CR)
327 void ahci_irq_handler() {
328 qemu_warn(
"AHCI interrupt!");
330 uint32_t status = abar->interrupt_status;
332 abar->interrupt_status = status;
334 for(
int i = 0; i < 32; i++) {
335 if(status & (1 << i)) {
336 volatile AHCI_HBA_PORT* port = AHCI_PORT(i);
338 uint32_t port_interrupt_status = port->interrupt_status;
340 port->interrupt_status = port_interrupt_status;
349 bool ahci_send_cmd(
volatile AHCI_HBA_PORT *port,
size_t slot) {
351 while ((port->task_file_data & (ATA_SR_BSY | ATA_SR_DRQ)) && spin < 1000000) {
355 if (spin == 1000000) {
356 qemu_err(
"Port is hung");
360 qemu_warn(
"DRIVE IS READY");
362 port->command_issue |= 1 << slot;
364 qemu_warn(
"COMMAND IS ISSUED");
367 if (~port->command_issue & (1 << slot))
370 if (port->interrupt_status & AHCI_HBA_TFES) {
371 qemu_err(
"Read disk error (Task file error); IS: %x", port->interrupt_status);
388 void ahci_read_sectors(
size_t port_num, uint64_t location,
size_t sector_count,
void* buffer) {
389 if(!ahci_initialized) {
390 qemu_err(
"AHCI not present!");
396 size_t block_size = desc.is_atapi ? 2048 : 512;
398 qemu_warn(
"\033[7mAHCI READ STARTED\033[0m");
400 char* buffer_mem = kmalloc_common(sector_count * block_size, PAGE_SIZE);
401 memset(buffer_mem, 0, sector_count * block_size);
403 size_t buffer_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) buffer_mem);
405 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
407 port->interrupt_status = (uint32_t)-1;
412 hdr->a = desc.is_atapi ? 1 : 0;
416 qemu_log(
"FIS IS %d DWORDs long", hdr->cfl);
422 size_t bytes = sector_count * block_size;
427 for(i = 0; i < bytes; i += (4 * MB) - 1) {
428 table->prdt_entry[index].dba = buffer_phys + i;
429 table->prdt_entry[index].dbau = 0;
430 table->prdt_entry[index].rsv0 = 0;
431 table->prdt_entry[index].dbc = MIN((4 * MB), (bytes - i) % (4 * MB)) - 1;
432 table->prdt_entry[index].rsv1 = 0;
433 table->prdt_entry[index].i = 0;
435 qemu_log(
"PRDT[%d]: Address: %x; Size: %d bytes; Last: %d",
437 table->prdt_entry[index].dba,
438 table->prdt_entry[index].dbc + 1,
439 table->prdt_entry[index].i);
444 table->prdt_entry[index - 1].i = 1;
450 qemu_log(
"CMDFIS at: %p", cmdfis);
452 cmdfis->fis_type = FIS_TYPE_REG_HOST_TO_DEVICE;
454 cmdfis->command = desc.is_atapi ? ATA_CMD_PACKET : ATA_CMD_READ_DMA_EXT;
457 qemu_log(
"ATAPI DEVICE");
462 (location >> 0x18) & 0xFF,
463 (location >> 0x10) & 0xFF,
464 (location >> 0x08) & 0xFF,
465 (location >> 0x00) & 0xFF,
466 (sector_count >> 0x18) & 0xFF,
467 (sector_count >> 0x10) & 0xFF,
468 (sector_count >> 0x08) & 0xFF,
469 (sector_count >> 0x00) & 0xFF,
474 memcpy(table->acmd, command, 12);
476 size_t bytecount = sector_count * 2048;
478 cmdfis->lba0 = bytecount & 0xff;
479 cmdfis->lba1 = (bytecount >> 8) & 0xff;
480 cmdfis->lba2 = (bytecount >> 16) & 0xff;
482 qemu_log(
"JUST A DISK DEVICE");
484 cmdfis->lba0 = location & 0xFF;
485 cmdfis->lba1 = (location >> 8) & 0xFF;
486 cmdfis->lba2 = (location >> 16) & 0xFF;
487 cmdfis->lba3 = (location >> 24) & 0xFF;
488 cmdfis->lba4 = (location >> 32) & 0xFF;
489 cmdfis->lba5 = (location >> 40) & 0xFF;
491 cmdfis->countl = sector_count & 0xffU;
492 cmdfis->counth = (sector_count >> 8) & 0xffU;
494 cmdfis->device = 1U << 6;
497 ahci_send_cmd(port, 0);
499 memcpy(buffer, buffer_mem, bytes);
503 qemu_warn(
"\033[7mOK?\033[0m");
513 void ahci_write_sectors(
size_t port_num,
size_t location,
size_t sector_count,
void* buffer) {
514 if(!ahci_initialized) {
515 qemu_err(
"AHCI not present!");
519 qemu_warn(
"\033[7mAHCI WRITE STARTED\033[0m");
521 char* buffer_mem = kmalloc_common(sector_count * 512, PAGE_SIZE);
522 memset(buffer_mem, 0, sector_count * 512);
523 memcpy(buffer_mem, buffer, sector_count * 512);
525 size_t buffer_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) buffer_mem);
527 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
529 port->interrupt_status = (uint32_t)-1;
538 qemu_log(
"FIS IS %d DWORDs long", hdr->cfl);
544 size_t bytes = sector_count * 512;
549 for(i = 0; i < bytes; i += (4 * MB) - 1) {
550 table->prdt_entry[index].dba = buffer_phys + i;
551 table->prdt_entry[index].dbau = 0;
552 table->prdt_entry[index].rsv0 = 0;
553 table->prdt_entry[index].dbc = MIN((4 * MB), (bytes - i) % (4 * MB)) - 1;
554 table->prdt_entry[index].rsv1 = 0;
555 table->prdt_entry[index].i = 0;
557 qemu_log(
"PRDT[%d]: Address: %x; Size: %d bytes; Last: %d",
559 table->prdt_entry[index].dba,
560 table->prdt_entry[index].dbc + 1,
561 table->prdt_entry[index].i);
566 table->prdt_entry[index - 1].i = 1;
572 qemu_log(
"CMDFIS at: %p", cmdfis);
574 cmdfis->fis_type = FIS_TYPE_REG_HOST_TO_DEVICE;
576 cmdfis->command = ATA_CMD_WRITE_DMA_EXT;
578 cmdfis->lba0 = location & 0xFF;
579 cmdfis->lba1 = (location >> 8) & 0xFF;
580 cmdfis->lba2 = (location >> 16) & 0xFF;
581 cmdfis->device = 1 << 6;
583 cmdfis->lba3 = (location >> 24) & 0xFF;
584 cmdfis->countl = sector_count & 0xff;
585 cmdfis->counth = (sector_count >> 8) & 0xff;
587 ahci_send_cmd(port, 0);
591 qemu_warn(
"\033[7mOK?\033[0m");
596 void ahci_eject_cdrom(
size_t port_num) {
597 qemu_log(
"Trying to eject %d", port_num);
599 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
601 port->interrupt_status = (uint32_t)-1;
614 uint8_t command[10] = {
615 ATAPI_CMD_START_STOP,
621 memcpy(table->acmd, command, 10);
626 cmdfis->fis_type = FIS_TYPE_REG_HOST_TO_DEVICE;
628 cmdfis->command = ATA_CMD_PACKET;
630 ahci_send_cmd(port, 0);
633 void ahci_read(
size_t port_num, uint8_t* buf, uint64_t location, uint32_t length) {
635 qemu_log(
"Buffer is nullptr!");
641 size_t block_size = ports[port_num].is_atapi ? 2048 : 512;
643 uint64_t start_sector = location / block_size;
644 uint64_t end_sector = (location + length - 1) / block_size;
645 uint64_t sector_count = end_sector - start_sector + 1;
647 uint64_t real_length = sector_count * block_size;
649 qemu_log(
"Reading %d sectors...", (uint32_t)sector_count);
651 uint8_t* real_buf = kmalloc(real_length);
653 ahci_read_sectors(port_num, start_sector, sector_count, real_buf);
655 memcpy(buf, real_buf + (location % block_size), length);
660 size_t ahci_dpm_read(
size_t Disk, uint64_t high_offset, uint64_t low_offset,
size_t Size,
void* Buffer){
663 DPM_Disk dpm = dpm_info(Disk + 65);
665 ahci_read((
size_t) dpm.Point, Buffer, low_offset, Size);
670 size_t ahci_dpm_write(
size_t Disk, uint64_t high_offset, uint64_t low_offset,
size_t Size,
void* Buffer){
671 qemu_err(
"TODO: SATA DPM WRITE");
679 void ahci_identify(
size_t port_num,
bool is_atapi) {
680 qemu_log(
"Identifying %d", port_num);
682 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
684 port->interrupt_status = (uint32_t)-1;
688 uint32_t block_size = 512;
699 void* memory = kmalloc_common(512, PAGE_SIZE);
700 size_t buffer_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) memory);
707 table->prdt_entry[0].dba = buffer_phys;
708 table->prdt_entry[0].dbc = 0x1ff;
709 table->prdt_entry[0].i = 0;
713 cmdfis->fis_type = FIS_TYPE_REG_HOST_TO_DEVICE;
716 cmdfis->command = ATA_CMD_IDENTIFY_PACKET;
719 cmdfis->command = ATA_CMD_IDENTIFY;
724 ahci_send_cmd(port, slot);
726 uint16_t* memory16 = (uint16_t*)memory;
728 size_t capacity = (memory16[101] << 16) | memory16[100];
730 uint16_t* model = kcalloc(20, 2);
732 for(
int i = 0; i < 20; i++) {
733 model[i] = bit_flip_short(memory16[0x1b + i]);
736 *(((uint8_t*)model) + 39) = 0;
738 tty_printf(
"[SATA] MODEL: '%s'; CAPACITY: %d sectors\n", model, capacity);
742 (
char)dpm_searchFreeIndex(0),
746 capacity * block_size,
755 qemu_err(
"[SATA/DPM] [ERROR] An error occurred during disk registration, error code: %d", disk_inx);
757 qemu_ok(
"[SATA/DPM] [Successful] Registering OK");
758 dpm_fnc_write(disk_inx + 65, &ahci_dpm_read, &ahci_dpm_write);
762 ports[port_num].is_atapi = is_atapi;
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 * 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
uint32_t pci_read32(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
Чтение данных из шины PCI.
void sleep_ms(uint32_t milliseconds)
Ожидание по миллисекундам