SayoriOS 0.3.3

ahci.c
1 #include "drv/disk/ahci.h"
2
3 #include <lib/math.h>
4
5 #include "drv/pci.h"
6 #include "io/ports.h"
7 #include "io/tty.h"
8 #include "mem/pmm.h"
9 #include "mem/vmm.h"
10 #include "sys/isr.h"
11 #include "drv/disk/ata.h"
12 #include "drv/atapi.h"
13 #include "net/endianess.h"
14 #include "drv/disk/dpm.h"
15 //#include "debug/hexview.h"
16
17 #define AHCI_CLASS 1
18 #define AHCI_SUBCLASS 6
19
20 struct ahci_port_descriptor ports[32] = {0};
21
22 uint8_t ahci_busnum, ahci_slot, ahci_func;
23 uint16_t ahci_vendor = 0, ahci_devid = 0;
24 uint32_t ahci_irq;
25 bool ahci_initialized = false;
26
27 volatile AHCI_HBA_MEM* abar;
28
29 // #undef qemu_log
30 // #undef qemu_err
31 // #undef qemu_warn
32 // #undef qemu_ok
33 // #define qemu_log(M, ...) tty_printf(M "\n", ##__VA_ARGS__)
34 // #define qemu_err(M, ...) tty_printf("[ERR] " M "\n", ##__VA_ARGS__)
35 // #define qemu_warn(M, ...) tty_printf("[WARN] " M "\n", ##__VA_ARGS__)
36 // #define qemu_ok(M, ...) tty_printf("[OK] " M "\n", ##__VA_ARGS__)
37
38 #define AHCI_PORT(num) (abar->ports + (num))
39
40 //#define qemu_log(M, ...) _tty_printf(M "\n", ##__VA_ARGS__)
41
42 void ahci_irq_handler();
43
44 void ahci_init() {
45 // Find controller
46
47 pci_find_device_by_class_and_subclass(AHCI_CLASS, AHCI_SUBCLASS, &ahci_vendor, &ahci_devid, &ahci_busnum, &ahci_slot, &ahci_func);
48
49
50 if(ahci_vendor == 0 || ahci_devid == 0) {
51 qemu_err("AHCI contoller not found!");
52
53 return;
54 }
55
56 qemu_ok("Found VEN: %x DEV: %x", ahci_vendor, ahci_devid);
57
58 // Enable Bus Mastering
59 pci_enable_bus_mastering(ahci_busnum, ahci_slot, ahci_func);
60
61 // qemu_ok("Enabled Bus Mastering");
62
63 // Get ABAR
64
65 abar = (volatile AHCI_HBA_MEM*)(pci_read32(ahci_busnum, ahci_slot, ahci_func, 0x24) & ~0b1111U);
66
67 qemu_log("AHCI ABAR is: %p", abar);
68
69 // Map memory
70 map_pages(
71 get_kernel_page_directory(),
72 (physical_addr_t) abar,
73 (virtual_addr_t) abar,
74 PAGE_SIZE * 2,
75 PAGE_WRITEABLE | PAGE_CACHE_DISABLE
76 );
77
78 qemu_log("Version: %x", abar->version);
79
80 if(abar->host_capabilities_extended & 1U) {
81 for(int i = 0; i < 5; i++) {
82 qemu_warn("PERFORMING BIOS HANDOFF!!!");
83 }
84
85 abar->handoff_control_and_status = abar->handoff_control_and_status | (1 << 1);
86
87 while(1) {
88 size_t status = abar->handoff_control_and_status;
89
90 if (~status & (1 << 0)) {
91 break;
92 }
93 }
94 } else {
95 qemu_ok("No BIOS Handoff");
96 }
97
98 // Reset
99 abar->global_host_control = (1 << 31) /* | (1 << 0) */; // Just enable AHCI
100
101 // while(true) {
102 // if((abar->global_host_control & 1) == 0) {
103 // break;
104 // }
105 // }
106
107 // Interrupts
108 ahci_irq = pci_read_confspc_word(ahci_busnum, ahci_slot, ahci_func, 0x3C) & 0xFF; // All 0xF PCI register
109 qemu_log("AHCI IRQ: %x (%d)", ahci_irq, ahci_irq);
110
111 register_interrupt_handler(32 + ahci_irq, ahci_irq_handler);
112
113 // Init
114 abar->global_host_control |= (1 << 0); // Reset
115
116 while((abar->global_host_control & 1) == 1)
117 ;
118
119 tty_printf("Reset okay");
120
121 abar->global_host_control |= (1 << 31) | (1 << 1); // AHCI Enable and AHCI Interrupts
122
123 qemu_ok("Enabled AHCI and INTERRUPTS");
124
125 size_t caps = abar->capability;
126 size_t slotCount = ((caps >> 8) & 0x1f) + 1;
127
128 qemu_log("Slot count: %d", slotCount);
129
130 size_t maxports = (caps & 0x1f) + 1;
131
132 qemu_log("Max port count: %d", maxports);
133
134 // Scan bus
135
136 uint32_t implemented_ports = abar->port_implemented;
137
138 qemu_log("PI is: %x", implemented_ports);
139
140 for(uint32_t i = 0; i < 32; i++) {
141 if (implemented_ports & (1 << i)) {
142 AHCI_HBA_PORT* port = AHCI_PORT(i);
143
144 // Additional initialization here
145
146 if((port->command_and_status & (1 << 2)) != (1 << 2)) {
147 port->command_and_status |= (1 << 2);
148
149 sleep_ms(200); // Replace them with checks
150 }
151
152 if((port->command_and_status & (1 << 1)) != (1 << 1)) {
153 port->sata_error = 0xFFFFFFFF;
154
155 port->sata_control = 0;
156
157 port->command_and_status |= (1 << 1); // Spin up.
158
159 sleep_ms(100); // Replace them with checks
160 }
161
162 if (!ahci_is_drive_attached(i)) {
163 continue;
164 }
165
166 port->sata_error = 0xFFFFFFFF;
167
168 // Idk why we are clearing START bit.
169 port->command_and_status = port->command_and_status & 0xfffffffe;
170
171 while(port->command_and_status & (1 << 15))
172 ;
173
174 tty_printf("[%d] AFTER CMD = %x\n", i, port->command_and_status);
175
176 ahci_rebase_memory_for(i);
177 }
178 }
179
180 for(int i = 0; i < 32; i++) {
181 if(abar->port_implemented & (1 << i)) {
182 volatile AHCI_HBA_PORT* port = abar->ports + i;
183
184 qemu_log("[%p: Port %d]", port, i);
185
186 if(!ahci_is_drive_attached(i)) {
187 qemu_log("\tNo drive attached to port!");
188 continue;
189 }
190
191 if(port->signature == AHCI_SIGNATURE_SATAPI) { // SATAPI
192 qemu_log("\tSATAPI drive");
193 ahci_identify(i, true);
194 ahci_eject_cdrom(i);
195 } else if(port->signature == AHCI_SIGNATURE_SATA) { // SATA
196 qemu_log("\tSATA drive");
197 ahci_identify(i, false);
198 } else {
199 qemu_log("Other device: %x", port->signature);
200 }
201 }
202 }
203
204 ahci_initialized = true;
205 }
206
207 void ahci_rebase_memory_for(size_t port_num) {
208 if(port_num > 31)
209 return;
210
211 ahci_stop_cmd(port_num);
212
213 // Memory rebase
214 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
215
216 void* virt = kmalloc_common(MEMORY_PER_AHCI_PORT, PAGE_SIZE);
217 memset(virt, 0, MEMORY_PER_AHCI_PORT);
218
219 // If gets laggy, comment it.
220 phys_set_flags(get_kernel_page_directory(), (virtual_addr_t) virt, PAGE_WRITEABLE | PAGE_CACHE_DISABLE);
221
222 size_t phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) virt);
223
224 ports[port_num].command_list_addr_virt = virt;
225 ports[port_num].command_list_addr_phys = phys;
226
227 ports[port_num].fis_virt = AHCI_FIS(virt, 0);
228 ports[port_num].fis_phys = AHCI_FIS(phys, 0);
229
230 // qemu_log("Virtual addresses: Command list %x, FIS %x", ports[port_num].command_list_addr_virt, ports[port_num].fis_virt);
231
232 port->command_list_base_address_low = phys;
233 port->command_list_base_address_high = 0;
234
235 port->fis_base_address_low = AHCI_FIS(phys, 0);
236 port->fis_base_address_high = 0;
237
238 AHCI_HBA_CMD_HEADER *cmdheader = (AHCI_HBA_CMD_HEADER*)virt;
239
240 for(int i = 0; i < 32; i++) {
241 cmdheader[i].prdtl = COMMAND_TABLE_PRDT_ENTRY_COUNT;
242
243 cmdheader[i].ctba = AHCI_COMMAND_TABLE_ENTRY(phys, 0, i);
244
245 cmdheader[i].ctbau = 0;
246 }
247
248 // qemu_log("Port %d", port_num);
249 // qemu_log("\t|- CMD LIST BASE: %x (%s)", port->command_list_base_address_low, IS_ALIGNED(port->command_list_base_address_low, 1024) ? "aligned" : "not aligned");
250 // qemu_log("\t|- FIS BASE: %x (%s)", port->fis_base_address_low, IS_ALIGNED(port->fis_base_address_low, 256) ? "aligned" : "not aligned");
251 // qemu_log("\t|- TABLE ENTRIES: %x - %x", cmdheader[0].ctba, cmdheader[31].ctba + 256);
252
253 ahci_start_cmd(port_num);
254
255 qemu_ok("Rebasing memory for: %d is OK.", port_num);
256 }
257
258 bool ahci_is_drive_attached(size_t port_num) {
259 if(port_num > 31){
260 return false;
261 }
262
263 uint32_t implemented_ports = abar->port_implemented;
264
265 if(implemented_ports & (1 << port_num)) {
266 volatile AHCI_HBA_PORT* port = abar->ports + port_num;
267
268 uint32_t status = port->sata_status;
269
270 uint8_t ipm = (status >> 8) & 0xF;
271 uint8_t det = status & 0xF;
272
273 if(ipm == 1 && det == 3) {
274 return true;
275 }
276 }
277
278 return false;
279 }
280
281 int ahci_free_cmd_slot(size_t port_num) {
282 if(port_num > 31)
283 return -1;
284
285 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
286
287 uint32_t slots = port->sata_active | port->command_issue;
288
289 for(int i = 0; i < 32; i++) {
290 if((slots & (1 << i)) == 0)
291 return i;
292 }
293
294 return -1;
295 }
296
297 void ahci_start_cmd(size_t port_num) {
298 if(port_num > 31)
299 return;
300
301 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
302
303 while (port->command_and_status & AHCI_HBA_CR);
304
305 port->command_and_status |= AHCI_HBA_FRE;
306 port->command_and_status |= AHCI_HBA_ST;
307 }
308
309 void ahci_stop_cmd(size_t port_num) {
310 if(port_num > 31)
311 return;
312
313 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
314
315 port->command_and_status &= ~AHCI_HBA_ST;
316 port->command_and_status &= ~AHCI_HBA_FRE;
317
318 while(1) {
319 if (port->command_and_status & AHCI_HBA_FR)
320 continue;
321 if (port->command_and_status & AHCI_HBA_CR)
322 continue;
323 break;
324 }
325 }
326
327 void ahci_irq_handler() {
328 qemu_warn("AHCI interrupt!");
329
330 uint32_t status = abar->interrupt_status;
331
332 abar->interrupt_status = status;
333
334 for(int i = 0; i < 32; i++) {
335 if(status & (1 << i)) {
336 volatile AHCI_HBA_PORT* port = AHCI_PORT(i);
337
338 uint32_t port_interrupt_status = port->interrupt_status;
339
340 port->interrupt_status = port_interrupt_status;
341
342 // if(port_interrupt_status == 0) {
343 // continue;
344 // }
345 }
346 }
347 }
348
349 bool ahci_send_cmd(volatile AHCI_HBA_PORT *port, size_t slot) {
350 int spin = 0;
351 while ((port->task_file_data & (ATA_SR_BSY | ATA_SR_DRQ)) && spin < 1000000) {
352 spin++;
353 }
354
355 if (spin == 1000000) {
356 qemu_err("Port is hung");
357 return false;
358 }
359
360 qemu_warn("DRIVE IS READY");
361
362 port->command_issue |= 1 << slot;
363
364 qemu_warn("COMMAND IS ISSUED");
365
366 while (1) {
367 if (~port->command_issue & (1 << slot)) // Command is not running? Break
368 break;
369
370 if (port->interrupt_status & AHCI_HBA_TFES) { // Task file error? Tell about error and exit
371 qemu_err("Read disk error (Task file error); IS: %x", port->interrupt_status);
372
373 return false;
374 }
375 }
376
377 qemu_warn("OK");
378 return true;
379 }
380
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!");
391 return;
392 }
393
394 struct ahci_port_descriptor desc = ports[port_num];
395
396 size_t block_size = desc.is_atapi ? 2048 : 512;
397
398 qemu_warn("\033[7mAHCI READ STARTED\033[0m");
399
400 char* buffer_mem = kmalloc_common(sector_count * block_size, PAGE_SIZE);
401 memset(buffer_mem, 0, sector_count * block_size);
402
403 size_t buffer_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) buffer_mem);
404
405 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
406
407 port->interrupt_status = (uint32_t)-1;
408
409 AHCI_HBA_CMD_HEADER* hdr = ports[port_num].command_list_addr_virt;
410
411 hdr->cfl = sizeof(AHCI_FIS_REG_DEVICE_TO_HOST) / sizeof(uint32_t); // Should be 5
412 hdr->a = desc.is_atapi ? 1 : 0; // ATAPI / Not ATAPI
413 hdr->w = 0; // Read
414 hdr->p = 0; // No prefetch
415
416 qemu_log("FIS IS %d DWORDs long", hdr->cfl);
417
418 HBA_CMD_TBL* table = (HBA_CMD_TBL*)AHCI_COMMAND_TABLE(ports[port_num].command_list_addr_virt, 0);
419
420 memset(table, 0, sizeof(HBA_CMD_TBL));
421
422 size_t bytes = sector_count * block_size;
423
424 // FIXME: Simplify statements
425 int index = 0;
426 int i;
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; // Size in bytes 4M max
432 table->prdt_entry[index].rsv1 = 0;
433 table->prdt_entry[index].i = 0;
434
435 qemu_log("PRDT[%d]: Address: %x; Size: %d bytes; Last: %d",
436 i,
437 table->prdt_entry[index].dba,
438 table->prdt_entry[index].dbc + 1,
439 table->prdt_entry[index].i);
440
441 index++;
442 }
443
444 table->prdt_entry[index - 1].i = 1;
445
446 hdr->prdtl = index;
447
448 AHCI_FIS_REG_HOST_TO_DEVICE *cmdfis = (AHCI_FIS_REG_HOST_TO_DEVICE*)&(table->cfis);
449
450 qemu_log("CMDFIS at: %p", cmdfis);
451
452 cmdfis->fis_type = FIS_TYPE_REG_HOST_TO_DEVICE;
453 cmdfis->c = 1; // Command
454 cmdfis->command = desc.is_atapi ? ATA_CMD_PACKET : ATA_CMD_READ_DMA_EXT;
455
456 if(desc.is_atapi) {
457 qemu_log("ATAPI DEVICE");
458
459 char command[12] = {
460 ATAPI_CMD_READ, // Command
461 0, // ?
462 (location >> 0x18) & 0xFF, // LBA
463 (location >> 0x10) & 0xFF,
464 (location >> 0x08) & 0xFF,
465 (location >> 0x00) & 0xFF,
466 (sector_count >> 0x18) & 0xFF, // Sector count
467 (sector_count >> 0x10) & 0xFF,
468 (sector_count >> 0x08) & 0xFF,
469 (sector_count >> 0x00) & 0xFF,
470 0, // ?
471 0 // ?
472 };
473
474 memcpy(table->acmd, command, 12);
475
476 size_t bytecount = sector_count * 2048;
477
478 cmdfis->lba0 = bytecount & 0xff;
479 cmdfis->lba1 = (bytecount >> 8) & 0xff;
480 cmdfis->lba2 = (bytecount >> 16) & 0xff;
481 } else {
482 qemu_log("JUST A DISK DEVICE");
483
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;
490
491 cmdfis->countl = sector_count & 0xffU;
492 cmdfis->counth = (sector_count >> 8) & 0xffU;
493
494 cmdfis->device = 1U << 6; // LBA mode
495 }
496
497 ahci_send_cmd(port, 0);
498
499 memcpy(buffer, buffer_mem, bytes);
500
501 kfree(buffer_mem);
502
503 qemu_warn("\033[7mOK?\033[0m");
504 }
505
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!");
516 return;
517 }
518
519 qemu_warn("\033[7mAHCI WRITE STARTED\033[0m");
520
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);
524
525 size_t buffer_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) buffer_mem);
526
527 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
528
529 port->interrupt_status = (uint32_t)-1;
530
531 AHCI_HBA_CMD_HEADER* hdr = ports[port_num].command_list_addr_virt;
532
533 hdr->cfl = sizeof(AHCI_FIS_REG_DEVICE_TO_HOST) / sizeof(uint32_t); // Should be 5
534 hdr->a = 0; // Not ATAPI
535 hdr->w = 1; // Write
536 hdr->p = 0; // No prefetch
537
538 qemu_log("FIS IS %d DWORDs long", hdr->cfl);
539
540 HBA_CMD_TBL* table = (HBA_CMD_TBL*)AHCI_COMMAND_TABLE(ports[port_num].command_list_addr_virt, 0);
541
542 memset(table, 0, sizeof(HBA_CMD_TBL));
543
544 size_t bytes = sector_count * 512;
545
546 // FIXME: Simplify statements
547 int index = 0;
548 int i;
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; // Size in bytes 4M max
554 table->prdt_entry[index].rsv1 = 0;
555 table->prdt_entry[index].i = 0;
556
557 qemu_log("PRDT[%d]: Address: %x; Size: %d bytes; Last: %d",
558 i,
559 table->prdt_entry[index].dba,
560 table->prdt_entry[index].dbc + 1,
561 table->prdt_entry[index].i);
562
563 index++;
564 }
565
566 table->prdt_entry[index - 1].i = 1;
567
568 hdr->prdtl = index;
569
570 AHCI_FIS_REG_HOST_TO_DEVICE *cmdfis = (AHCI_FIS_REG_HOST_TO_DEVICE*)&(table->cfis);
571
572 qemu_log("CMDFIS at: %p", cmdfis);
573
574 cmdfis->fis_type = FIS_TYPE_REG_HOST_TO_DEVICE;
575 cmdfis->c = 1; // Command
576 cmdfis->command = ATA_CMD_WRITE_DMA_EXT;
577
578 cmdfis->lba0 = location & 0xFF;
579 cmdfis->lba1 = (location >> 8) & 0xFF;
580 cmdfis->lba2 = (location >> 16) & 0xFF;
581 cmdfis->device = 1 << 6; // LBA mode
582
583 cmdfis->lba3 = (location >> 24) & 0xFF;
584 cmdfis->countl = sector_count & 0xff;
585 cmdfis->counth = (sector_count >> 8) & 0xff;
586
587 ahci_send_cmd(port, 0);
588
589 kfree(buffer_mem);
590
591 qemu_warn("\033[7mOK?\033[0m");
592 }
593
594
595 // Call SCSI START_STOP command to eject a disc
596 void ahci_eject_cdrom(size_t port_num) {
597 qemu_log("Trying to eject %d", port_num);
598
599 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
600
601 port->interrupt_status = (uint32_t)-1;
602
603 AHCI_HBA_CMD_HEADER* hdr = ports[port_num].command_list_addr_virt;
604
605 hdr->cfl = sizeof(AHCI_FIS_REG_DEVICE_TO_HOST) / sizeof(uint32_t); // Should be 5
606 hdr->a = 1; // ATAPI
607 hdr->w = 0; // Read
608 hdr->p = 0; // No prefetch
609 hdr->prdtl = 0; // No entries
610
611 HBA_CMD_TBL* table = (HBA_CMD_TBL*)AHCI_COMMAND_TABLE(ports[port_num].command_list_addr_virt, 0);
612 memset(table, 0, sizeof(HBA_CMD_TBL));
613
614 uint8_t command[10] = {
615 ATAPI_CMD_START_STOP, // Command
616 0, 0, 0, // Reserved
617 1 << 1, // Eject the disc
618 0, 0, 0, 0, 0 // Reserved
619 };
620
621 memcpy(table->acmd, command, 10);
622
623 volatile AHCI_FIS_REG_HOST_TO_DEVICE *cmdfis = (volatile AHCI_FIS_REG_HOST_TO_DEVICE*)&(table->cfis);
624 memset((void*)cmdfis, 0, sizeof(AHCI_FIS_REG_HOST_TO_DEVICE));
625
626 cmdfis->fis_type = FIS_TYPE_REG_HOST_TO_DEVICE;
627 cmdfis->c = 1; // Command
628 cmdfis->command = ATA_CMD_PACKET;
629
630 ahci_send_cmd(port, 0);
631 }
632
633 void ahci_read(size_t port_num, uint8_t* buf, uint64_t location, uint32_t length) {
634 ON_NULLPTR(buf, {
635 qemu_log("Buffer is nullptr!");
636 return;
637 });
638
639 // TODO: Get sector size somewhere (Now we hardcode it into 512).
640
641 size_t block_size = ports[port_num].is_atapi ? 2048 : 512;
642
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;
646
647 uint64_t real_length = sector_count * block_size;
648
649 qemu_log("Reading %d sectors...", (uint32_t)sector_count);
650
651 uint8_t* real_buf = kmalloc(real_length);
652
653 ahci_read_sectors(port_num, start_sector, sector_count, real_buf);
654
655 memcpy(buf, real_buf + (location % block_size), length);
656
657 kfree(real_buf);
658 }
659
660 size_t ahci_dpm_read(size_t Disk, uint64_t high_offset, uint64_t low_offset, size_t Size, void* Buffer){
661 // qemu_err("TODO: SATA DPM READ");
662
663 DPM_Disk dpm = dpm_info(Disk + 65);
664
665 ahci_read((size_t) dpm.Point, Buffer, low_offset, Size);
666
667 return Size;
668 }
669
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");
672
673 // DPM_Disk dpm = dpm_info(Disk + 65);
674
675 return 0;
676 }
677
678
679 void ahci_identify(size_t port_num, bool is_atapi) {
680 qemu_log("Identifying %d", port_num);
681
682 volatile AHCI_HBA_PORT* port = AHCI_PORT(port_num);
683
684 port->interrupt_status = (uint32_t)-1;
685
686 int slot = 0;
687
688 uint32_t block_size = 512;
689
690 AHCI_HBA_CMD_HEADER* hdr = ports[port_num].command_list_addr_virt;
691 hdr += slot;
692
693 hdr->cfl = sizeof(AHCI_FIS_REG_DEVICE_TO_HOST) / sizeof(uint32_t); // Should be 5
694 hdr->a = 0; // IDENTIFY COMMANDS DOES NOT NEED TO SET ATAPI FLAG
695 hdr->w = 0; // Read
696 hdr->p = 0; // No prefetch
697 hdr->prdtl = 1; // One entry only
698
699 void* memory = kmalloc_common(512, PAGE_SIZE);
700 size_t buffer_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) memory);
701 memset(memory, 0, 512);
702
703 HBA_CMD_TBL* table = (HBA_CMD_TBL*)AHCI_COMMAND_TABLE(ports[port_num].command_list_addr_virt, 0);
704 memset(table, 0, sizeof(HBA_CMD_TBL));
705
706 // Set only first PRDT for testing
707 table->prdt_entry[0].dba = buffer_phys;
708 table->prdt_entry[0].dbc = 0x1ff; // 512 bytes - 1
709 table->prdt_entry[0].i = 0;
710
711 volatile AHCI_FIS_REG_HOST_TO_DEVICE *cmdfis = (volatile AHCI_FIS_REG_HOST_TO_DEVICE*)&(table->cfis);
712
713 cmdfis->fis_type = FIS_TYPE_REG_HOST_TO_DEVICE;
714 cmdfis->c = 1; // Command
715 if(is_atapi) {
716 cmdfis->command = ATA_CMD_IDENTIFY_PACKET;
717 block_size = 2048;
718 } else {
719 cmdfis->command = ATA_CMD_IDENTIFY;
720 }
721
722 cmdfis->lba1 = 0;
723
724 ahci_send_cmd(port, slot);
725
726 uint16_t* memory16 = (uint16_t*)memory;
727
728 size_t capacity = (memory16[101] << 16) | memory16[100];
729
730 uint16_t* model = kcalloc(20, 2);
731
732 for(int i = 0; i < 20; i++) {
733 model[i] = bit_flip_short(memory16[0x1b + i]);
734 }
735
736 *(((uint8_t*)model) + 39) = 0;
737
738 tty_printf("[SATA] MODEL: '%s'; CAPACITY: %d sectors\n", model, capacity);
739
740 if(!is_atapi) {
741 int disk_inx = dpm_reg(
742 (char)dpm_searchFreeIndex(0),
743 "SATA Disk",
744 "Unknown",
745 1,
746 capacity * block_size,
747 capacity,
748 block_size,
749 3, // Ставим 3ку, так как будем юзать функции для чтения и записи
750 "DISK1234567890",
751 (void*)port_num // Оставим тут индекс диска
752 );
753
754 if (disk_inx < 0){
755 qemu_err("[SATA/DPM] [ERROR] An error occurred during disk registration, error code: %d", disk_inx);
756 } else {
757 qemu_ok("[SATA/DPM] [Successful] Registering OK");
758 dpm_fnc_write(disk_inx + 65, &ahci_dpm_read, &ahci_dpm_write);
759 }
760 }
761
762 ports[port_num].is_atapi = is_atapi;
763
764 kfree(memory);
765 kfree(model);
766 }
dpm_reg
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] Регистрация дискового раздела
Definition: dpm.c:187
memset
void * memset(void *ptr, char value, size_t num)
Заполнение массива указанными символами
Definition: string.c:203
memcpy
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173
pci_read_confspc_word
uint16_t pci_read_confspc_word(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
[PCI] Чтение 16-битных полей из пространства механизма конфигураций 1
Definition: pci.c:32
pci_read32
uint32_t pci_read32(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
Чтение данных из шины PCI.
Definition: pci.c:54
AHCI_FIS_REG_DEVICE_TO_HOST
Definition: ahci.h:102
AHCI_FIS_REG_HOST_TO_DEVICE
Definition: ahci.h:68
AHCI_HBA_CMD_HEADER
Definition: ahci.h:197
HBA_CMD_TBL
Definition: ahci.h:269
ahci_port_descriptor
Definition: ahci.h:293
sleep_ms
void sleep_ms(uint32_t milliseconds)
Ожидание по миллисекундам
Definition: timer.c:68