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 }
__attribute__
struct registers __attribute__((packed))
Структура данных пакета от мыши
Definition: psf.h:19
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
memcpy
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173
ata_drive_t
Эта структура определяет каждый ATA диск в системе
Definition: ata.h:102
ata_drive_t::is_dma
bool is_dma
Является ли этот диск SATA устройством?
Definition: ata.h:118
ata_drive_t::model_name
char * model_name
Поддерживает ли этот диск DMA?
Definition: ata.h:120
ata_drive_t::block_size
uint16_t block_size
Адресация по CHS?
Definition: ata.h:111
ata_drive_t::capacity
size_t capacity
Устройство доступно?
Definition: ata.h:105
ata_drive_t::is_packet
bool is_packet
Ёмкость диска в секторах
Definition: ata.h:107
registers
Definition: common.h:59