Skip to content

Commit e27633d

Browse files
Fixed AHCI to now support multiple opening of files. In future multiple PRDTs will be used for max speed transfer
1 parent 43498cf commit e27633d

3 files changed

Lines changed: 94 additions & 49 deletions

File tree

source/includes/ahci.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
#define MAX_PARTITIONS 128
3030
#define MAX_BLOCK_DEVICES 64
3131

32+
#define AHCI_MAX_PRDT 16 // 8,16 OR 32
33+
#define PRDT_MAX_BYTES (4 * 1024 * 1024) // 4 KiB
34+
3235

3336
/**
3437
* @brief AHCI device signatures.
@@ -80,7 +83,7 @@ typedef struct __attribute__((packed)) {
8083
uint8_t cfis[64];
8184
uint8_t acmd[16];
8285
uint8_t reserved[48];
83-
prdt_entry_t prdt[1]; /* flexible / variable sized in allocation */
86+
prdt_entry_t prdt[AHCI_MAX_PRDT]; /* flexible / variable sized in allocation */
8487
} ahci_cmd_table_t;
8588

8689
typedef struct {

source/kernel/C/ahci.c

Lines changed: 88 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ static inline void ahci_unlock_port_io(int portno)
3737
__sync_lock_release(&ahci_port_io_lock[portno]);
3838
}
3939

40+
static int ahci_find_free_slot(ahci_port_t* port)
41+
{
42+
uint32_t slots = port->sact | port->ci;
43+
44+
for (int i = 0; i < 32; i++) {
45+
if (!(slots & (1 << i)))
46+
return i;
47+
}
48+
49+
return -1; // no free slot
50+
}
51+
4052
static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t count);
4153
static int ahci_write_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t count);
4254

@@ -460,23 +472,25 @@ static int ahci_wait_slot0_ready(ahci_port_t* port)
460472
return -1;
461473
}
462474

463-
static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t count) {
475+
static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t count)
476+
{
464477
int rc = 0;
465478
ahci_port_t* port = &global_ahci_ctrl->ports[portno];
466479
ahci_port_mem_t* mem = &port_mem[portno];
480+
467481
ahci_lock_port_io(portno);
468482

469-
while (port->tfd & (0x80 | 0x08));
483+
while (port->tfd & (0x80 | 0x08)); // BSY | DRQ
470484

471-
int slot = 0;
472-
if (ahci_wait_slot0_ready(port) != 0) {
485+
int slot = ahci_find_free_slot(port);
486+
if (slot < 0) {
473487
rc = -1;
474488
goto out;
475489
}
476490

477491
ahci_cmd_header_t* hdr = &mem->cmd_list[slot];
478492
memset(hdr, 0, sizeof(*hdr));
479-
hdr->flags = 5;
493+
hdr->flags = (5 & AHCI_CMD_HDR_CFL_MASK); // CFL = 5 DWORDS
480494
hdr->prdtl = 1;
481495
hdr->ctba = (uint32_t)(uintptr_t)mem->cmd_tables[slot];
482496
hdr->ctbau = 0;
@@ -485,7 +499,13 @@ static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t
485499
memset(tbl->cfis, 0, 64);
486500
memset(tbl->prdt, 0, sizeof(tbl->prdt));
487501

488-
tbl->prdt[0].dba = (uint32_t)(uintptr_t)buffer;
502+
void* dma_buf = kmalloc_aligned(count * 512, 4096);
503+
if (!dma_buf) {
504+
rc = -10;
505+
goto out;
506+
}
507+
508+
tbl->prdt[0].dba = (uint32_t)(uintptr_t)dma_buf;
489509
tbl->prdt[0].dbau = 0;
490510
tbl->prdt[0].dbc = (count * 512 - 1) | (1 << 31);
491511

@@ -494,19 +514,21 @@ static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t
494514
cfis[1] = 1 << 7;
495515
cfis[2] = READ_DMA_EXT;
496516

497-
cfis[4] = (uint8_t)lba;
498-
cfis[5] = (uint8_t)(lba >> 8);
499-
cfis[6] = (uint8_t)(lba >> 16);
500-
cfis[7] = 0x40;
501-
cfis[8] = (uint8_t)(lba >> 24);
502-
cfis[9] = (uint8_t)(lba >> 32);
517+
cfis[4] = (uint8_t)lba;
518+
cfis[5] = (uint8_t)(lba >> 8);
519+
cfis[6] = (uint8_t)(lba >> 16);
520+
cfis[7] = 0x40;
521+
cfis[8] = (uint8_t)(lba >> 24);
522+
cfis[9] = (uint8_t)(lba >> 32);
503523
cfis[10] = (uint8_t)(lba >> 40);
524+
504525
cfis[12] = count & 0xFF;
505526
cfis[13] = (count >> 8) & 0xFF;
506527

507528
port->serr = 0xFFFFFFFF;
508-
port->is = 0xFFFFFFFF;
529+
port->is = 0xFFFFFFFF;
509530

531+
__sync_synchronize();
510532
port->ci = 1 << slot;
511533

512534
while (port->ci & (1 << slot)) {
@@ -517,28 +539,33 @@ static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t
517539
}
518540

519541
port->is = 0xFFFFFFFF;
542+
520543
out:
544+
memcpy(buffer, dma_buf, count * 512);
545+
kfree(dma_buf);
521546
ahci_unlock_port_io(portno);
522547
return rc;
523548
}
524549

525-
static int ahci_write_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t count) {
550+
static int ahci_write_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t count)
551+
{
526552
int rc = 0;
527553
ahci_port_t* port = &global_ahci_ctrl->ports[portno];
528554
ahci_port_mem_t* mem = &port_mem[portno];
555+
529556
ahci_lock_port_io(portno);
530557

531-
while (port->tfd & (0x80 | 0x08));
558+
while (port->tfd & (0x80 | 0x08)); // BSY | DRQ
532559

533-
int slot = 0;
534-
if (ahci_wait_slot0_ready(port) != 0) {
560+
int slot = ahci_find_free_slot(port);
561+
if (slot < 0) {
535562
rc = -1;
536563
goto out;
537564
}
538565

539566
ahci_cmd_header_t* hdr = &mem->cmd_list[slot];
540567
memset(hdr, 0, sizeof(*hdr));
541-
hdr->flags = 5 | AHCI_CMD_HDR_W_BIT;
568+
hdr->flags = (5 & AHCI_CMD_HDR_CFL_MASK) | AHCI_CMD_HDR_W_BIT;
542569
hdr->prdtl = 1;
543570
hdr->ctba = (uint32_t)(uintptr_t)mem->cmd_tables[slot];
544571
hdr->ctbau = 0;
@@ -547,7 +574,13 @@ static int ahci_write_sector_raw(int portno, uint64_t lba, void* buffer, uint32_
547574
memset(tbl->cfis, 0, 64);
548575
memset(tbl->prdt, 0, sizeof(tbl->prdt));
549576

550-
tbl->prdt[0].dba = (uint32_t)(uintptr_t)buffer;
577+
void* dma_buf = kmalloc_aligned(count * 512, 4096);
578+
if (!dma_buf) {
579+
rc = -10;
580+
goto out;
581+
}
582+
583+
tbl->prdt[0].dba = (uint32_t)(uintptr_t)dma_buf;
551584
tbl->prdt[0].dbau = 0;
552585
tbl->prdt[0].dbc = (count * 512 - 1) | (1 << 31);
553586

@@ -556,91 +589,99 @@ static int ahci_write_sector_raw(int portno, uint64_t lba, void* buffer, uint32_
556589
cfis[1] = 1 << 7;
557590
cfis[2] = ATA_CMD_WRITE_DMA_EXT;
558591

559-
cfis[4] = (uint8_t)lba;
560-
cfis[5] = (uint8_t)(lba >> 8);
561-
cfis[6] = (uint8_t)(lba >> 16);
562-
cfis[7] = 0x40;
563-
cfis[8] = (uint8_t)(lba >> 24);
564-
cfis[9] = (uint8_t)(lba >> 32);
592+
cfis[4] = (uint8_t)lba;
593+
cfis[5] = (uint8_t)(lba >> 8);
594+
cfis[6] = (uint8_t)(lba >> 16);
595+
cfis[7] = 0x40;
596+
cfis[8] = (uint8_t)(lba >> 24);
597+
cfis[9] = (uint8_t)(lba >> 32);
565598
cfis[10] = (uint8_t)(lba >> 40);
599+
566600
cfis[12] = count & 0xFF;
567601
cfis[13] = (count >> 8) & 0xFF;
568602

569603
port->serr = 0xFFFFFFFF;
570-
port->is = 0xFFFFFFFF;
604+
port->is = 0xFFFFFFFF;
571605

606+
__sync_synchronize();
572607
port->ci = 1 << slot;
573608

574609
while (port->ci & (1 << slot)) {
575-
if (port->tfd & (0x01 | 0x20)) { // ERR | DF
576-
port->is = 0xFFFFFFFF;
577-
printf("[AHCI] Write error! tfd=0x%X\n", port->tfd);
610+
if (port->tfd & (0x01 | 0x20)) {
578611
rc = -3;
579612
goto out;
580613
}
581614
}
582615

583616
port->is = 0xFFFFFFFF;
617+
584618
out:
619+
memcpy(dma_buf, buffer, count * 512);
620+
kfree(dma_buf);
585621
ahci_unlock_port_io(portno);
586622
return rc;
587623
}
588624

589-
int ahci_identify(int portno, void* buffer) {
625+
int ahci_identify(int portno, void* buffer)
626+
{
590627
int rc = 0;
591628
ahci_port_t* port = &global_ahci_ctrl->ports[portno];
592629
ahci_port_mem_t* mem = &port_mem[portno];
630+
593631
ahci_lock_port_io(portno);
594632

595-
// Wait until port is ready
596-
while (port->tfd & (0x80 | 0x08)); // BSY | DRQ
633+
while (port->tfd & (0x80 | 0x08));
597634

598-
int slot = 0;
599-
if (ahci_wait_slot0_ready(port) != 0) {
635+
int slot = ahci_find_free_slot(port);
636+
if (slot < 0) {
600637
rc = -1;
601638
goto out;
602639
}
603640

604641
ahci_cmd_header_t* hdr = &mem->cmd_list[slot];
605642
memset(hdr, 0, sizeof(*hdr));
606-
hdr->flags = 5;
607-
hdr->prdtl = 1; // one PRDT entry
643+
hdr->flags = (5 & AHCI_CMD_HDR_CFL_MASK); // CFL = 5 DWORDS
644+
hdr->prdtl = 1;
608645
hdr->ctba = (uint32_t)(uintptr_t)mem->cmd_tables[slot];
609646
hdr->ctbau = 0;
610647

611-
612648
ahci_cmd_table_t* tbl = mem->cmd_tables[slot];
613649
memset(tbl->cfis, 0, 64);
614650
memset(tbl->prdt, 0, sizeof(tbl->prdt));
615651

652+
void* dma_buf = kmalloc_aligned(512, 4096);
653+
if (!dma_buf) {
654+
rc = -10;
655+
goto out;
656+
}
616657

617-
tbl->prdt[0].dba = (uint32_t)(uintptr_t)buffer;
658+
tbl->prdt[0].dba = (uint32_t)(uintptr_t)dma_buf;
618659
tbl->prdt[0].dbau = 0;
619-
tbl->prdt[0].dbc = (512 - 1) | (1 << 31); // 512 bytes, IOC
660+
tbl->prdt[0].dbc = (512 - 1) | (1 << 31);
620661

621662
uint8_t* cfis = tbl->cfis;
622-
cfis[0] = 0x27; // Host to device
623-
cfis[1] = 1 << 7; // Command
624-
cfis[2] = ATA_CMD_IDENTIFY; // IDENTIFY DEVICE
625-
cfis[7] = 0; // Features = 0
626-
cfis[8] = 0; cfis[9] = 0; cfis[10] = 0; // LBA = 0
663+
cfis[0] = 0x27;
664+
cfis[1] = 1 << 7;
665+
cfis[2] = ATA_CMD_IDENTIFY;
627666

628667
port->serr = 0xFFFFFFFF;
629668
port->is = 0xFFFFFFFF;
630669

670+
__sync_synchronize();
631671
port->ci = 1 << slot;
632672

633-
// Wait for completion
634673
while (port->ci & (1 << slot)) {
635-
if (port->tfd & (0x01 | 0x20)) { // ERR | DF
636-
port->is = 0xFFFFFFFF;
674+
if (port->tfd & (0x01 | 0x20)) {
637675
rc = -2;
638676
goto out;
639677
}
640678
}
641679

642680
port->is = 0xFFFFFFFF;
681+
643682
out:
683+
memcpy(buffer, dma_buf, 512);
684+
kfree(dma_buf);
644685
ahci_unlock_port_io(portno);
645686
return rc;
646687
}

source/kernel/C/syscalls.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1188,7 +1188,8 @@ uint64_t syscall_dispatch (
11881188
return sys_futex((uint32_t*)arg1, arg2, arg3,
11891189
(const linux_timespec_t*)arg4,
11901190
(uint32_t*)arg5, arg6);
1191-
1191+
case 41: // getuid (32-bit ABI compatibility)
1192+
return 0;
11921193
case 19:
11931194
{
11941195
linux_iovec_t* iov = (linux_iovec_t*)arg2;

0 commit comments

Comments
 (0)