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 }
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
void * memset(void *ptr, char value, size_t num)
Заполнение массива указанными символами
Definition: string.c:203
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173
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
uint32_t pci_read32(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
Чтение данных из шины PCI.
Definition: pci.c:54
void sleep_ms(uint32_t milliseconds)
Ожидание по миллисекундам
Definition: timer.c:68