SayoriOS  0.3.3
ata.c
1 #include "drv/disk/ata.h"
2 #include <io/ports.h>
3 #include <drv/atapi.h>
4 #include <mem/vmm.h>
5 #include <io/tty.h>
6 #include "drv/disk/dpm.h"
7 #include "sys/isr.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"
13 
14 // TODO: Move ATA PIO functions into ata_pio.c for code clarity
15 
16 #define DEFAULT_TIMEOUT (65535 * 2)
17 
18 const char possible_dpm_letters_for_ata[4] = "CDEF";
19 ata_drive_t drives[4] = {0};
20 
21 bool ide_poll_drq(uint16_t io) {
22  while(1) {
23  uint8_t status = inb(io + ATA_REG_STATUS);
24  if(status & ATA_SR_DRQ) {
25  return true;
26  } else if ((status & ATA_SR_ERR) || (status & ATA_SR_DF)) {
27  return false;
28  }
29  }
30 }
31 
32 bool ide_poll_bsy(uint16_t io) {
33  while(1) {
34  uint8_t status = inb(io + ATA_REG_STATUS);
35  if(!(status & ATA_SR_BSY)) {
36  return true;
37  } else if ((status & ATA_SR_ERR) || (status & ATA_SR_DF)) {
38  return false;
39  }
40  }
41 }
42 
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)));
46  else
47  outb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, (0xA0 | ((uint8_t)slave << 4)));
48 }
49 
50 void ide_primary_irq(__attribute__((unused)) registers_t regs) {
51 // qemu_log("=================== Got ATA interrupt. PRIMARY");
52 
53 // uint8_t status = inb(ATA_PRIMARY_IO + ATA_REG_STATUS);
54  inb(ATA_PRIMARY_IO + ATA_REG_STATUS);
55 
56 // qemu_log("Status: %d (%x); Altstatus: %x", status, status, altstatus);
57 }
58 
59 void ide_secondary_irq(__attribute__((unused)) registers_t regs) {
60 // qemu_log("=================== Got ATA interrupt. SECONDARY");
61 
62 // size_t status = inb(ATA_SECONDARY_IO + ATA_REG_STATUS);
63  inb(ATA_SECONDARY_IO + ATA_REG_STATUS);
64 
65 // qemu_log("Status: %d (%x); Altstatus: %x", status, status, altstatus);
66 }
67 
68 void ide_soft_reset(size_t io) {
69  outb(io + ATA_REG_CONTROL, 0x04);
70  ide_400ns_delay(io);
71  outb(io + ATA_REG_CONTROL, 0);
72 }
73 
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);
77 // qemu_note("[ATA] [DPM] [DISK %d] [READ] Off: %d | Size: %d", dpm.Point, Offset, Size);
78  // TODO: @ndraey не забудь для своей функции сделать кол-во полученных байт
79  // FIXME: For those who want to see thid piece of code: I literally burned my eyes with this.
80  ata_read((uint8_t) dpm.Point, Buffer, low_offset, Size);
81  return Size;
82 }
83 
84 
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);
88 // qemu_note("[ATA] [DPM] [DISK %d] [WRITE] Off: %d | Size: %d", dpm.Point, Offset, Size);
89  // TODO: @ndraey не забудь для своей функции сделать кол-во записанных байт
90  // FIXME: For those who want to see thid piece of code: I literally burned my eyes with this.
91  ata_write((uint8_t) dpm.Point, Buffer, low_offset, Size);
92  return Size;
93 }
94 
95 
96 uint8_t ide_identify(uint8_t bus, uint8_t drive) {
97  uint16_t io = (bus == ATA_PRIMARY) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO;
98 
99  uint8_t drive_num = (bus << 1) | drive;
100 
101  qemu_log("Identifying %s %s", PRIM_SEC(bus), MAST_SLV(drive));
102 
103  ide_soft_reset(io);
104  ide_select_drive(bus, drive);
105 
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);
110 
111  outb(io + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
112  qemu_log("Sent IDENTIFY");
113 
114  uint8_t status = inb(io + ATA_REG_STATUS);
115 
116  qemu_log("Status: %d; Err: %d", status, status & ATA_SR_ERR);
117 
118  size_t timeout = DEFAULT_TIMEOUT;
119 
120  uint16_t *ide_buf = kcalloc(512, 1);
121 
122  if(status) {
123  // In ATAPI, IDENTIFY command has ERROR bit set.
124 
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);
129 
130  qemu_warn("%x %x %x %x", seccount, lba_l, lba_m, lba_h);
131  // ^----- If they contain 0x01, 0x01, 0x14, 0xEB then the device is a packet device,
132  // and `IDENTIFY PACKET DEVICE` (0xA1) should be used.
133 
134  if(seccount == 0x01 && lba_l == 0x01 && lba_m == 0x14 && lba_h == 0xEB) {
135  // It's ATAPI device! Yoo-hooo!
136 
137  qemu_log("ATA Packet Device!");
138 
139  drives[drive_num].online = true;
140  drives[drive_num].is_packet = true;
141 
142  outb(io + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
143 
144  for(int i = 0; i < 256; i++) {
145  *(uint16_t *)(ide_buf + i) = inw(io + ATA_REG_DATA);
146  }
147 
148  uint16_t* fwver = kcalloc(8, 1);
149  uint16_t* model_name = kcalloc(40, 1);
150  uint16_t* serial = kcalloc(20, 1);
151 
152  memcpy(serial, ide_buf + 10, 20);
153  memcpy(fwver, ide_buf + 23, 8);
154  memcpy(model_name, ide_buf + 27, 40);
155 
156  for(int i = 0; i < 10; i++) {
157  serial[i] = bit_flip_short(serial[i]);
158  }
159 
160  for(int i = 0; i < 4; i++) {
161  fwver[i] = bit_flip_short(fwver[i]);
162  }
163 
164  for(int i = 0; i < 20; i++) {
165  model_name[i] = bit_flip_short(model_name[i]);
166  }
167 
168  // Zero-terminate the strings
169  ((uint8_t*)serial)[19] = 0;
170  ((uint8_t*)fwver)[7] = 0;
171  ((uint8_t*)model_name)[39] = 0;
172 
173 
174  // Do my best for processing packet device.
175 
176  drives[drive_num].capacity = atapi_read_size(bus, drive);
177  drives[drive_num].block_size = atapi_read_block_size(bus, drive);
178 
179  drives[drive_num].fwversion = (char *) fwver;
180  drives[drive_num].model_name = (char *) model_name;
181  drives[drive_num].serial_number = (char *) serial;
182 
183  qemu_log("Size is: %d", drives[drive_num].capacity);
184 
185  qemu_note("DRIVE: %d", drive_num);
186 
187  qemu_note("Serial: %s", serial);
188  qemu_note("Firmware version: %s", fwver);
189  qemu_note("Model name: %s", model_name);
190 
191  // (drive_num) is an index (0, 1, 2, 3) of disk
192  int disk_inx = dpm_reg(
193  possible_dpm_letters_for_ata[drive_num],
194  "CD\\DVD drive",
195  "Unknown",
196  1,
197  drives[drive_num].capacity * drives[drive_num].block_size,
198  drives[drive_num].capacity,
199  drives[drive_num].block_size,
200  3, // Ставим 3ку, так как будем юзать функции для чтения и записи
201  "DISK1234567890",
202  (void*)drive_num // Оставим тут индекс диска
203  );
204 
205  if (disk_inx < 0){
206  qemu_err("[ATA] [DPM] [ERROR] An error occurred during disk registration, error code: %d",disk_inx);
207  } else {
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);
210  }
211 
212  kfree(ide_buf);
213 
214  return 0;
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)");
217  kfree(ide_buf);
218  return 1;
219  }
220 
221  /* Now, poll until BSY is clear. */
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));
226  kfree(ide_buf);
227  return 1;
228  }
229 
230  if(!timeout) {
231  qemu_log("ATA Timeout expired!");
232  kfree(ide_buf);
233  return 1;
234  } else {
235  timeout--;
236  }
237 
238  status = inb(io + ATA_REG_STATUS);
239  }
240 
241  timeout = DEFAULT_TIMEOUT;
242 
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));
247  kfree(ide_buf);
248  return 1;
249  }
250 
251  if(!timeout) {
252  qemu_log("ATA Timeout expired!");
253  kfree(ide_buf);
254  return 1;
255  }
256 
257  timeout--;
258 
259  status = inb(io + ATA_REG_STATUS);
260  }
261 
262  drives[drive_num].online = true;
263 
264  qemu_log("%s %s is online.", PRIM_SEC(bus), MAST_SLV(drive));
265 
266  for(int i = 0; i < 256; i++) {
267  *(uint16_t *)(ide_buf + i) = inw(io + ATA_REG_DATA);
268  }
269 
270  // Dump model and firmware version
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);
274 
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;
278 
279  memcpy(serial, ide_buf + 10, 20);
280  memcpy(fwver, ide_buf + 23, 8);
281  memcpy(model_name, ide_buf + 27, 40);
282 
283  for(int i = 0; i < 10; i++) {
284  serial[i] = bit_flip_short(serial[i]);
285  }
286 
287  for(int i = 0; i < 4; i++) {
288  fwver[i] = bit_flip_short(fwver[i]);
289  }
290 
291  for(int i = 0; i < 20; i++) {
292  model_name[i] = bit_flip_short(model_name[i]);
293  }
294 
295  // Zero-terminate the strings
296  ((uint8_t*)serial)[19] = 0;
297  ((uint8_t*)fwver)[7] = 0;
298  ((uint8_t*)model_name)[39] = 0;
299 
300  // size_t capacity = (ide_buf[61] << 16) | ide_buf[60]; // 28-bit value
301  size_t capacity = (ide_buf[101] << 16) | ide_buf[100]; // 64-bit value
302 
303  qemu_log("CAP: %u", capacity);
304 
305  drives[drive_num].drive = drive_num;
306  drives[drive_num].block_size = 512;
307  drives[drive_num].capacity = capacity;
308  drives[drive_num].is_dma = (ide_buf[49] & 0x200) ? true : false;
309 
310  // (drive_num) is an index (0, 1, 2, 3) of disk
311  int disk_inx = dpm_reg(
312  possible_dpm_letters_for_ata[drive_num],
313  "ATA IDE Disk",
314  "Unknown",
315  1,
316  capacity * 512,
317  capacity,
318  drives[drive_num].block_size,
319  3, // Ставим 3ку, так как будем юзать функции для чтения и записи
320  "DISK1234567890",
321  (void*)drive_num // Оставим тут индекс диска
322  );
323 
324  if (disk_inx < 0){
325  qemu_err("[ATA] [DPM] [ERROR] An error occurred during disk registration, error code: %d",disk_inx);
326  } else {
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);
329  }
330 
331 
332  qemu_log("Identify finished");
333  }else{
334  qemu_err("%s %s => No status. Drive may be disconnected!", PRIM_SEC(bus), MAST_SLV(drive));
335 
336  kfree(ide_buf);
337  return 1;
338  }
339 
340  kfree(ide_buf);
341  return 0;
342 }
343 
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);
349 }
350 
351 void ide_poll(uint16_t io) {
352  ide_400ns_delay(io);
353 
354  uint8_t status __attribute__((unused)) = inb(io + ATA_REG_STATUS);
355 
356  while(1) {
357  status = inb(io + ATA_REG_STATUS);
358 
359  if(!(status & ATA_SR_BSY))
360  break;
361  }
362 
363  while(1) {
364  status = inb(io + ATA_REG_STATUS);
365  if(status & ATA_SR_ERR) {
366  qemu_err("ERR set, device failure!\n");
367  break;
368  }
369 
370  if(status & ATA_SR_DRQ)
371  break;
372  }
373 }
374 
375 // UNTESTED
376 void ata_read(uint8_t drive, uint8_t* buf, uint32_t location, uint32_t length) {
377  ON_NULLPTR(buf, {
378  qemu_log("Buffer is nullptr!");
379  return;
380  });
381 
382  if(!drives[drive].online) {
383  qemu_log("Attempted read from drive that does not exist.");
384  return;
385  }
386 
387  if((!drives[drive].is_packet) && drives[drive].is_dma) {
388  ata_dma_read(drive, (char*)buf, location, length);
389  return;
390  }
391 
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;
395 
396  size_t real_length = sector_count * drives[drive].block_size;
397 
398 // qemu_log("Reading %d sectors...", sector_count);
399 
400  uint8_t* real_buf = kmalloc(real_length);
401 
402  // Add DMA support
403  if(!drives[drive].is_packet) {
404  ata_pio_read_sectors(drive, real_buf, start_sector, sector_count);
405  } else {
406  atapi_read_sectors(drive, real_buf, start_sector, sector_count);
407  }
408 
409  memcpy(buf, real_buf + (location % drives[drive].block_size), length);
410 
411  kfree(real_buf);
412 }
413 
414 void ata_write(uint8_t drive, const uint8_t* buf, size_t location, size_t length) {
415  ON_NULLPTR(buf, {
416  qemu_log("Buffer is nullptr!");
417  return;
418  });
419 
420  if(!drives[drive].online) {
421  qemu_log("Attempted read from drive that does not exist.");
422  return;
423  }
424 
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;
428 
429  uint8_t* temp_buf = kmalloc(sector_count * drives[drive].block_size);
430 
431  ata_pio_read_sectors(drive, temp_buf, start_sector, sector_count);
432 
433  size_t start_offset = location % drives[drive].block_size;
434  memcpy(temp_buf + start_offset, buf, length);
435 
436  ata_pio_write_sectors(drive, temp_buf, start_sector, sector_count);
437 
438  kfree(temp_buf);
439 }
440 
441 void ata_list() {
442  for (size_t i = 0; i < 4; i++) {
443  _tty_printf("\tATA: %s %s: %s ",
444  PRIM_SEC((i >> 1) & 1),
445  MAST_SLV(i & 1),
446  drives[i].online?"online ":"offline"
447  );
448 
449  if(!drives[i].online) {
450  _tty_printf("\n");
451  continue;
452  }
453 
454  _tty_printf("%u sectors = ", drives[i].capacity);
455 
456  size_t megabytes;
457 
458  if(drives[i].is_packet) {
459  megabytes = (drives[i].capacity * 2048) >> 20;
460  } else {
461  megabytes = (drives[i].capacity >> 5) / (1 << 6);
462  }
463 
464  _tty_printf("%u MB = %u GB", megabytes, megabytes >> 10);
465 
466  if(drives[i].is_packet)
467  _tty_printf(" [PACKET DEVICE!!!]");
468 
469  if(drives[i].is_sata)
470  _tty_printf(" [SATA]");
471 
472  if(drives[i].is_dma)
473  _tty_printf(" [DMA]");
474 
475  qemu_note("Drive %d", i);
476  qemu_note("'%s' '%s' '%s'", drives[i].model_name, drives[i].fwversion, drives[i].serial_number);
477 
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);
480 
481  _tty_printf("\n");
482  }
483 
484  tty_printf("\n");
485 }
486 
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);
492 }
493 
494 void ata_init() {
495  qemu_log("Checking for ATA drives");
496 
497  register_interrupt_handler(32 + ATA_PRIMARY_IRQ, ide_primary_irq); // Fuck IRQs
498  register_interrupt_handler(32 + ATA_SECONDARY_IRQ, ide_secondary_irq);
499 
500  ata_check_all();
501 }
struct registers __attribute__((packed))
Структура данных пакета от мыши
Definition: psf.h:19
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 * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173
Эта структура определяет каждый ATA диск в системе
Definition: ata.h:102
bool is_dma
Является ли этот диск SATA устройством?
Definition: ata.h:118
char * model_name
Поддерживает ли этот диск DMA?
Definition: ata.h:120
uint16_t block_size
Адресация по CHS?
Definition: ata.h:111
size_t capacity
Устройство доступно?
Definition: ata.h:105
bool is_packet
Ёмкость диска в секторах
Definition: ata.h:107