123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- #include "ahci.h"
- #include <common/kprint.h>
- #include <mm/slab.h>
- #include <syscall/syscall.h>
- #include <syscall/syscall_num.h>
- struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES];
- struct block_device_request_queue ahci_req_queue;
- uint32_t count_ahci_devices = 0;
- static uint64_t ahci_port_base_vaddr;
- static uint64_t ahci_port_base_phys_addr;
- static void start_cmd(HBA_PORT *port);
- static void stop_cmd(HBA_PORT *port);
- static void port_rebase(HBA_PORT *port, int portno);
- static long ahci_query_disk();
- static int ahci_find_cmdslot(HBA_PORT *port);
- #define cal_HBA_MEM_VIRT_ADDR(device_num) (AHCI_MAPPING_BASE + (ul)(((struct pci_device_structure_general_device_t *)(ahci_devs[device_num]))->BAR5 - ((((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5) & PAGE_2M_MASK)))
- void ahci_init()
- {
- kinfo("Initializing AHCI...");
- pci_get_device_structure(0x1, 0x6, ahci_devs, &count_ahci_devices);
- if (count_ahci_devices == 0)
- {
- kwarn("There is no AHCI device found on this computer!");
- return;
- }
-
- kdebug("phys_2_virt(ahci_devs[0])= %#018lx", (ahci_devs[0]));
- kdebug("((struct pci_device_structure_general_device_t *)phys_2_virt(ahci_devs[0])))->BAR5= %#018lx", ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5);
- uint32_t bar5 = ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5;
- mm_map_phys_addr(AHCI_MAPPING_BASE, (ul)(bar5)&PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
- kdebug("ABAR mapped!");
- for (int i = 0; i < count_ahci_devices; ++i)
- {
-
-
- ahci_devices[i].dev_struct = ahci_devs[i];
- ahci_devices[i].hba_mem = (HBA_MEM *)(cal_HBA_MEM_VIRT_ADDR(i));
- kdebug("ahci_devices[i].hba_mem = %#018lx", (ul)ahci_devices[i].hba_mem);
- }
-
- ahci_port_base_vaddr = (uint64_t)kmalloc(1048576, 0);
- kdebug("ahci_port_base_vaddr=%#018lx", ahci_port_base_vaddr);
- ahci_probe_port(0);
- port_rebase(&ahci_devices[0].hba_mem->ports[0], 0);
-
- ahci_req_queue.in_service = NULL;
- wait_queue_init(&ahci_req_queue.wait_queue_list, NULL);
- ahci_req_queue.request_count = 0;
- kinfo("AHCI initialized.");
- }
- static int check_type(HBA_PORT *port)
- {
- uint32_t ssts = port->ssts;
- uint8_t ipm = (ssts >> 8) & 0x0F;
- uint8_t det = ssts & 0x0F;
- if (det != HBA_PORT_DET_PRESENT)
- return AHCI_DEV_NULL;
- if (ipm != HBA_PORT_IPM_ACTIVE)
- return AHCI_DEV_NULL;
- switch (port->sig)
- {
- case SATA_SIG_ATAPI:
- return AHCI_DEV_SATAPI;
- case SATA_SIG_SEMB:
- return AHCI_DEV_SEMB;
- case SATA_SIG_PM:
- return AHCI_DEV_PM;
- default:
- return AHCI_DEV_SATA;
- }
- }
- static void ahci_probe_port(const uint32_t device_num)
- {
- HBA_MEM *abar = ahci_devices[device_num].hba_mem;
- uint32_t pi = abar->pi;
- for (int i = 0; i < 32; ++i, (pi >>= 1))
- {
- if (pi & 1)
- {
- uint dt = check_type(&abar->ports[i]);
- ahci_devices[i].type = dt;
- if (dt == AHCI_DEV_SATA)
- {
- kdebug("SATA drive found at port %d", i);
- }
- else if (dt == AHCI_DEV_SATAPI)
- {
- kdebug("SATAPI drive found at port %d", i);
- }
- else if (dt == AHCI_DEV_SEMB)
- {
- kdebug("SEMB drive found at port %d", i);
- }
- else if (dt == AHCI_DEV_PM)
- {
- kdebug("PM drive found at port %d", i);
- }
- else
- {
-
- }
- }
- }
- }
- static void start_cmd(HBA_PORT *port)
- {
-
- while ((port->cmd) & HBA_PxCMD_CR)
- ;
-
- port->cmd |= HBA_PxCMD_FRE;
- port->cmd |= HBA_PxCMD_ST;
- }
- static void stop_cmd(HBA_PORT *port)
- {
-
- port->cmd &= ~HBA_PxCMD_ST;
-
- port->cmd &= ~HBA_PxCMD_FRE;
-
- while (1)
- {
- if (port->cmd & HBA_PxCMD_FR)
- continue;
- if (port->cmd & HBA_PxCMD_CR)
- continue;
- break;
- }
- }
- static void port_rebase(HBA_PORT *port, int portno)
- {
-
-
-
- stop_cmd(port);
-
-
-
-
- port->clb = virt_2_phys(ahci_port_base_vaddr + (portno << 10));
- memset((void *)(phys_2_virt(port->clb)), 0, 1024);
-
-
- port->fb = virt_2_phys(ahci_port_base_vaddr + (32 << 10) + (portno << 8));
- memset((void *)(phys_2_virt(port->fb)), 0, 256);
-
-
- HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)(phys_2_virt(port->clb));
- for (int i = 0; i < 32; ++i)
- {
- cmdheader[i].prdtl = 8;
-
-
- cmdheader[i].ctba = virt_2_phys((ahci_port_base_vaddr + (40 << 10) + (portno << 13) + (i << 8)));
- memset((void *)phys_2_virt(cmdheader[i].ctba), 0, 256);
- }
- start_cmd(port);
- }
- static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf)
- {
- port->is = (uint32_t)-1;
- int spin = 0;
- int slot = ahci_find_cmdslot(port);
- if (slot == -1)
- return E_NOEMPTYSLOT;
- HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb);
- cmdheader += slot;
- cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t);
- cmdheader->w = 0;
- cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1;
- HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL *)phys_2_virt(cmdheader->ctba);
- memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl - 1) * sizeof(HBA_PRDT_ENTRY));
-
- int i;
- for (i = 0; i < cmdheader->prdtl - 1; ++i)
- {
- cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
- cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1;
- cmdtbl->prdt_entry[i].i = 1;
- buf += 4 * 1024;
- count -= 16;
- }
-
- cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
- cmdtbl->prdt_entry[i].dbc = (count << 9) - 1;
- cmdtbl->prdt_entry[i].i = 1;
-
- FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&cmdtbl->cfis);
- cmdfis->fis_type = FIS_TYPE_REG_H2D;
- cmdfis->c = 1;
- cmdfis->command = AHCI_CMD_READ_DMA_EXT;
- cmdfis->lba0 = (uint8_t)startl;
- cmdfis->lba1 = (uint8_t)(startl >> 8);
- cmdfis->lba2 = (uint8_t)(startl >> 16);
- cmdfis->device = 1 << 6;
- cmdfis->lba3 = (uint8_t)(startl >> 24);
- cmdfis->lba4 = (uint8_t)starth;
- cmdfis->lba5 = (uint8_t)(starth >> 8);
- cmdfis->countl = count & 0xFF;
- cmdfis->counth = (count >> 8) & 0xFF;
-
- while ((port->tfd & (AHCI_DEV_BUSY | AHCI_DEV_DRQ)) && spin < 1000000)
- {
- spin++;
- }
- if (spin == 1000000)
- {
- kerror("Port is hung");
- return E_PORT_HUNG;
- }
- port->ci = 1 << slot;
- current_pcb->flags |= PF_NEED_SCHED;
- sched_cfs();
- int retval = AHCI_SUCCESS;
-
- while (1)
- {
-
-
- if ((port->ci & (1 << slot)) == 0)
- break;
- if (port->is & HBA_PxIS_TFES)
- {
- kerror("Read disk error");
- retval = E_TASK_FILE_ERROR;
- break;
- }
- }
-
- if (port->is & HBA_PxIS_TFES)
- {
- kerror("Read disk error");
- retval = E_TASK_FILE_ERROR;
- }
- enter_syscall_int(SYS_AHCI_END_REQ, 0, 0, 0, 0, 0, 0, 0, 0);
- return retval;
- }
- static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
- uint64_t buf)
- {
-
- port->is = 0xffff;
- int slot = ahci_find_cmdslot(port);
- if (slot == -1)
- return E_NOEMPTYSLOT;
- HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb);
- cmdheader += slot;
- cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t);
- cmdheader->w = 1;
- cmdheader->c = 1;
- cmdheader->p = 1;
- cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1;
- HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL *)phys_2_virt(cmdheader->ctba);
- memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl - 1) * sizeof(HBA_PRDT_ENTRY));
- int i = 0;
- for (i = 0; i < cmdheader->prdtl - 1; ++i)
- {
- cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
- cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1;
- cmdtbl->prdt_entry[i].i = 0;
- buf += 4 * 1024;
- count -= 16;
- }
- cmdtbl->prdt_entry[i].dba = virt_2_phys(buf);
- cmdtbl->prdt_entry[i].dbc = count << 9;
- cmdtbl->prdt_entry[i].i = 0;
- FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&cmdtbl->cfis);
- cmdfis->fis_type = FIS_TYPE_REG_H2D;
- cmdfis->c = 1;
- cmdfis->command = AHCI_CMD_WRITE_DMA_EXT;
- cmdfis->lba0 = (uint8_t)startl;
- cmdfis->lba1 = (uint8_t)(startl >> 8);
- cmdfis->lba2 = (uint8_t)(startl >> 16);
- cmdfis->lba3 = (uint8_t)(startl >> 24);
- cmdfis->lba4 = (uint8_t)starth;
- cmdfis->lba5 = (uint8_t)(starth >> 8);
- cmdfis->device = 1 << 6;
- cmdfis->countl = count & 0xff;
- cmdfis->counth = count >> 8;
-
- port->ci = 1;
-
- current_pcb->flags |= PF_NEED_SCHED;
- sched_cfs();
- int retval = AHCI_SUCCESS;
- while (1)
- {
-
-
- if ((port->ci & (1 << slot)) == 0)
- break;
- if (port->is & HBA_PxIS_TFES)
- {
- kerror("Write disk error");
- retval = E_TASK_FILE_ERROR;
- break;
- }
- }
- if (port->is & HBA_PxIS_TFES)
- {
- kerror("Write disk error");
- retval = E_TASK_FILE_ERROR;
- }
-
- enter_syscall_int(SYS_AHCI_END_REQ, 0, 0, 0, 0, 0, 0, 0, 0);
- return retval;
- }
- static int ahci_find_cmdslot(HBA_PORT *port)
- {
-
- uint32_t slots = (port->sact | port->ci);
- int num_of_cmd_clots = (ahci_devices[0].hba_mem->cap & 0x0f00) >> 8;
- for (int i = 0; i < num_of_cmd_clots; i++)
- {
- if ((slots & 1) == 0)
- return i;
- slots >>= 1;
- }
- kerror("Cannot find free command list entry");
- return -1;
- }
- long ahci_open()
- {
- return 0;
- }
- long ahci_close()
- {
- return 0;
- }
- static struct ahci_request_packet_t *ahci_make_request(long cmd, uint64_t base_addr, uint64_t count, uint64_t buffer, uint8_t ahci_ctrl_num, uint8_t port_num)
- {
- struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)kmalloc(sizeof(struct ahci_request_packet_t), 0);
- wait_queue_init(&pack->blk_pak.wait_queue, current_pcb);
- pack->blk_pak.device_type = BLK_TYPE_AHCI;
-
- switch (cmd)
- {
- case AHCI_CMD_READ_DMA_EXT:
- pack->blk_pak.end_handler = NULL;
- pack->blk_pak.cmd = AHCI_CMD_READ_DMA_EXT;
- break;
- case AHCI_CMD_WRITE_DMA_EXT:
- pack->blk_pak.end_handler = NULL;
- pack->blk_pak.cmd = AHCI_CMD_WRITE_DMA_EXT;
- break;
- default:
- pack->blk_pak.end_handler = NULL;
- pack->blk_pak.cmd = cmd;
- break;
- }
- pack->blk_pak.LBA_start = base_addr;
- pack->blk_pak.count = count;
- pack->blk_pak.buffer_vaddr = buffer;
- pack->ahci_ctrl_num = ahci_ctrl_num;
- pack->port_num = port_num;
- return pack;
- }
- void ahci_end_request()
- {
- ahci_req_queue.in_service->wait_queue.pcb->state = PROC_RUNNING;
-
-
- kfree((uint64_t *)ahci_req_queue.in_service);
- ahci_req_queue.in_service = NULL;
-
- if (ahci_req_queue.request_count > 0)
- ahci_query_disk();
- }
- static long ahci_query_disk()
- {
- wait_queue_node_t *wait_queue_tmp = container_of(list_next(&ahci_req_queue.wait_queue_list.wait_list), wait_queue_node_t, wait_list);
- struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)container_of(wait_queue_tmp, struct block_device_request_packet, wait_queue);
- ahci_req_queue.in_service = (struct block_device_request_packet *)pack;
- list_del(&(ahci_req_queue.in_service->wait_queue.wait_list));
- --ahci_req_queue.request_count;
- long ret_val;
-
- switch (pack->blk_pak.cmd)
- {
- case AHCI_CMD_READ_DMA_EXT:
- ret_val = ahci_read(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr);
- break;
- case AHCI_CMD_WRITE_DMA_EXT:
- ret_val = ahci_write(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr);
- break;
- default:
- kerror("Unsupport ahci command: %#05lx", pack->blk_pak.cmd);
- ret_val = E_UNSUPPORTED_CMD;
- break;
- }
-
- return ret_val;
- }
- static void ahci_submit(struct ahci_request_packet_t *pack)
- {
- list_append(&(ahci_req_queue.wait_queue_list.wait_list), &(pack->blk_pak.wait_queue.wait_list));
- ++ahci_req_queue.request_count;
- if (ahci_req_queue.in_service == NULL)
- ahci_query_disk();
- }
- static long ahci_transfer(long cmd, uint64_t base_addr, uint64_t count, uint64_t buf, uint8_t ahci_ctrl_num, uint8_t port_num)
- {
- struct ahci_request_packet_t *pack = NULL;
- if (cmd == AHCI_CMD_READ_DMA_EXT || cmd == AHCI_CMD_WRITE_DMA_EXT)
- {
- pack = ahci_make_request(cmd, base_addr, count, buf, ahci_ctrl_num, port_num);
- ahci_submit(pack);
- }
- else
- return E_UNSUPPORTED_CMD;
- return AHCI_SUCCESS;
- }
- static long ahci_ioctl(long cmd, long arg)
- {
- }
- struct block_device_operation ahci_operation =
- {
- .open = ahci_open,
- .close = ahci_close,
- .ioctl = ahci_ioctl,
- .transfer = ahci_transfer,
- };
|