From 6d286be29f1f461f1740994406bfe31ff448a6b4 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Sat, 2 Apr 2022 19:14:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90=E4=BA=86ah?= =?UTF-8?q?ci=E9=A9=B1=E5=8A=A8=E7=A8=8B=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 +- kernel/driver/disk/ahci/ahci.c | 200 ++++++++++++++++++++++++++---- kernel/driver/disk/ahci/ahci.h | 30 +++-- kernel/driver/disk/ata.c | 1 + kernel/driver/disk/block_device.h | 10 +- kernel/main.c | 13 +- 6 files changed, 214 insertions(+), 45 deletions(-) diff --git a/.gitignore b/.gitignore index c99bd1f7..56c2602b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ /cmake-build-debug/ /bin/ DragonOS.iso -.idea/ \ No newline at end of file +.idea/ + +*.o +*.s \ No newline at end of file diff --git a/kernel/driver/disk/ahci/ahci.c b/kernel/driver/disk/ahci/ahci.c index 9f23675a..aa39256c 100644 --- a/kernel/driver/disk/ahci/ahci.c +++ b/kernel/driver/disk/ahci/ahci.c @@ -11,6 +11,7 @@ uint64_t ahci_port_base_vaddr; // 端口映射base 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(); // Find a free command list slot static int ahci_find_cmdslot(HBA_PORT *port); @@ -25,7 +26,6 @@ void ahci_init() { pci_get_device_structure(0x1, 0x6, ahci_devs, &count_ahci_devices); - kdebug("phys addr=%#018lx", (ul)(((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5)); // 映射ABAR mm_map_phys_addr(AHCI_MAPPING_BASE, ((ul)(((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5)) & PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD); kdebug("ABAR mapped!"); @@ -40,15 +40,11 @@ void ahci_init() ahci_port_base_vaddr = (uint64_t)kmalloc(1048576, 0); ahci_probe_port(0); port_rebase(&ahci_devices[0].hba_mem->ports[0], 0); - uint64_t buf[100]; - bool res = ahci_read(&(ahci_devices[0].hba_mem->ports[0]), 0, 0, 1, (uint64_t)&buf); - kdebug("res=%d, buf[0]=%#010lx", (uint)res, (uint32_t)buf[0]); - buf[0] = 0xa0; - res = ahci_write(&(ahci_devices[0].hba_mem->ports[0]), 0, 0, 1, (uint64_t)&buf); - - res = ahci_read(&(ahci_devices[0].hba_mem->ports[0]), 0, 0, 1, (uint64_t)&buf); - kdebug("res=%d, buf[0]=%#010lx", (uint)res, (uint32_t)buf[0]); + // 初始化请求队列 + ahci_req_queue.in_service = NULL; + list_init(&(ahci_req_queue.queue_list)); + ahci_req_queue.request_count = 0; } // Check device type @@ -80,9 +76,9 @@ static int check_type(HBA_PORT *port) /** * @brief 检测端口连接的设备的类型 * - * @param device_num ahci设备号 + * @param device_num ahci控制器号 */ -void ahci_probe_port(const uint32_t device_num) +static void ahci_probe_port(const uint32_t device_num) { HBA_MEM *abar = ahci_devices[device_num].hba_mem; uint32_t pi = abar->pi; @@ -111,7 +107,7 @@ void ahci_probe_port(const uint32_t device_num) } else { - kdebug("No drive found at port %d", i); + // kdebug("No drive found at port %d", i); } } } @@ -200,14 +196,14 @@ static void port_rebase(HBA_PORT *port, int portno) * @return true done * @return false failed */ -bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf) +static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf) { port->is = (uint32_t)-1; // Clear pending interrupt bits int spin = 0; // Spin lock timeout counter int slot = ahci_find_cmdslot(port); if (slot == -1) - return false; + return E_NOEMPTYSLOT; HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)port->clb; cmdheader += slot; @@ -261,7 +257,7 @@ bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, if (spin == 1000000) { kerror("Port is hung"); - return false; + return E_PORT_HUNG; } kdebug("slot=%d", slot); @@ -277,7 +273,7 @@ bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, if (port->is & HBA_PxIS_TFES) // Task file error { kerror("Read disk error"); - return false; + return E_TASK_FILE_ERROR; } } @@ -285,20 +281,19 @@ bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, if (port->is & HBA_PxIS_TFES) { kerror("Read disk error"); - return false; + return E_TASK_FILE_ERROR; } - return true; + return AHCI_SUCCESS; } -bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, - uint64_t buf) +static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, + uint64_t buf) { - printk("Inside writeport \n "); port->is = 0xffff; // Clear pending interrupt bits int slot = ahci_find_cmdslot(port); if (slot == -1) - return false; + return E_NOEMPTYSLOT; HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)port->clb; @@ -313,7 +308,7 @@ bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count 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++) + for (i = 0; i < cmdheader->prdtl - 1; ++i) { cmdtbl->prdt_entry[i].dba = buf; cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes @@ -351,16 +346,16 @@ bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count if (port->is & HBA_PxIS_TFES) { // Task file error kerror("Write disk error"); - return false; + return E_TASK_FILE_ERROR; } } if (port->is & HBA_PxIS_TFES) { kerror("Write disk error"); - return false; + return E_TASK_FILE_ERROR; } - return true; + return AHCI_SUCCESS; } // Find a free command list slot @@ -377,4 +372,155 @@ static int ahci_find_cmdslot(HBA_PORT *port) } kerror("Cannot find free command list entry"); return -1; -} \ No newline at end of file +} + +long ahci_open() +{ + return 0; +} + +long ahci_close() +{ + return 0; +} + +/** + * @brief 创建ahci磁盘请求包 + * + * @param cmd 控制命令 + * @param base_addr 48位LBA地址 + * @param count total sectors to read + * @param buf 缓冲区线性地址 + * @param ahci_ctrl_num ahci控制器号 + * @param port_num ahci控制器端口号 + * @return struct block_device_request_packet* + */ +static struct block_device_request_packet *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 block_device_request_packet *pack = (struct block_device_request_packet *)kmalloc(sizeof(struct block_device_request_packet), 0); + + list_init(&pack->list); + + // 由于ahci不需要中断即可读取磁盘,因此end handler为空 + switch (cmd) + { + case ATA_CMD_READ_DMA_EXT: + pack->end_handler = NULL; + pack->cmd = ATA_CMD_READ_DMA_EXT; + break; + case ATA_CMD_WRITE_DMA_EXT: + pack->end_handler = NULL; + pack->cmd = ATA_CMD_WRITE_DMA_EXT; + break; + default: + pack->end_handler = NULL; + pack->cmd = cmd; + break; + } + + pack->LBA_start = base_addr; + pack->count = count; + pack->buffer_vaddr = buffer; + + pack->ahci_ctrl_num = ahci_ctrl_num; + pack->port_num = port_num; + return pack; +} + +/** + * @brief 结束磁盘请求 + * + */ +static void ahci_end_request() +{ + kfree((uint64_t *)ahci_req_queue.in_service); + ahci_req_queue.in_service = NULL; + + // 进行下一轮的磁盘请求 (由于未实现单独的io调度器,这里会造成长时间的io等待) + if (ahci_req_queue.request_count>0) + ahci_query_disk(); +} + +static long ahci_query_disk() +{ + struct block_device_request_packet *pack = container_of(list_next(&ahci_req_queue.queue_list), struct block_device_request_packet, list); + ahci_req_queue.in_service = pack; + list_del(&(ahci_req_queue.in_service->list)); + --ahci_req_queue.request_count; + + long ret_val; + + switch (pack->cmd) + { + case ATA_CMD_READ_DMA_EXT: + ret_val = ahci_read(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->LBA_start & 0xFFFFFFFF, ((pack->LBA_start) >> 32) & 0xFFFFFFFF, pack->count, pack->buffer_vaddr); + break; + case ATA_CMD_WRITE_DMA_EXT: + ret_val = ahci_write(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->LBA_start & 0xFFFFFFFF, ((pack->LBA_start) >> 32) & 0xFFFFFFFF, pack->count, pack->buffer_vaddr); + break; + default: + kerror("Unsupport ahci command: %#05lx", pack->cmd); + ret_val = E_UNSUPPORTED_CMD; + break; + } + ahci_end_request(); + return ret_val; +} + +/** + * @brief 将请求包提交到io队列 + * + * @param pack + */ +static void ahci_submit(struct block_device_request_packet *pack) +{ + list_append(&(ahci_req_queue.queue_list), &(pack->list)); + ++ahci_req_queue.request_count; + + if (ahci_req_queue.in_service == NULL) // 当前没有正在请求的io包,立即执行磁盘请求 + ahci_query_disk(); +} + +/** + * @brief ahci驱动程序的传输函数 + * + * @param cmd 控制命令 + * @param base_addr 48位LBA地址 + * @param count total sectors to read + * @param buf 缓冲区线性地址 + * @param ahci_ctrl_num ahci控制器号 + * @param port_num ahci控制器端口号 + * @return long + */ +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 block_device_request_packet *pack = NULL; + + if (cmd == ATA_CMD_READ_DMA_EXT || cmd == ATA_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; +} + +/** + * @brief todo: io控制器函数 + * + * @param cmd 命令 + * @param arg 参数 + * @return long + */ +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, +}; diff --git a/kernel/driver/disk/ahci/ahci.h b/kernel/driver/disk/ahci/ahci.h index b4b55f30..75fada40 100644 --- a/kernel/driver/disk/ahci/ahci.h +++ b/kernel/driver/disk/ahci/ahci.h @@ -4,6 +4,10 @@ #include "../../pci/pci.h" #include "../../../mm/mm.h" +/** + * @todo 加入io调度器(当操作系统实现了多进程之后要加入这个) + * + */ #define AHCI_MAPPING_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE+AHCI_MAPPING_OFFSET #define MAX_AHCI_DEVICES 100 @@ -21,6 +25,14 @@ #define HBA_PxIS_TFES (1 << 30) /* TFES - Task File Error Status */ +#define AHCI_SUCCESS 0 // 请求成功 +#define E_NOEMPTYSLOT 1 // 没有空闲的slot +#define E_PORT_HUNG 2 // 端口被挂起 +#define E_TASK_FILE_ERROR 3 // 任务文件错误 +#define E_UNSUPPORTED_CMD 4 // 不支持的命令 + +extern struct block_device_operation ahci_operation; + /** * @brief 在SATA3.0规范中定义的Frame Information Structure类型 * @@ -348,15 +360,9 @@ struct ahci_device_t struct block_device_request_queue ahci_req_queue; -/* -struct block_device_operation ahci_operation = - { - .open = ahci_open, - .close = ahci_close, - .ioctl = ahci_ioctl, - .transfer = ahci_transfer, -}; -*/ + + + /** * @brief 初始化ahci模块 @@ -369,7 +375,7 @@ void ahci_init(); * * @param device_num ahci设备号 */ -void ahci_probe_port(const uint32_t device_num); +static void ahci_probe_port(const uint32_t device_num); /** * @brief read data from SATA device using 48bit LBA address @@ -382,7 +388,7 @@ void ahci_probe_port(const uint32_t device_num); * @return true done * @return false failed */ -bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf); +static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf); /** * @brief write data to SATA device using 48bit LBA address @@ -395,5 +401,5 @@ bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, * @return true done * @return false failed */ -bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, +static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf); \ No newline at end of file diff --git a/kernel/driver/disk/ata.c b/kernel/driver/disk/ata.c index d3b04093..f67f5dfd 100644 --- a/kernel/driver/disk/ata.c +++ b/kernel/driver/disk/ata.c @@ -14,6 +14,7 @@ struct apic_IO_APIC_RTE_entry entry; void ata_disk_handler(ul irq_num, ul param, struct pt_regs *regs) { struct ata_identify_device_data info; + kdebug("irq_num=%ld", irq_num); // 从端口读入磁盘配置信息 diff --git a/kernel/driver/disk/block_device.h b/kernel/driver/disk/block_device.h index 157c8083..6925ba31 100644 --- a/kernel/driver/disk/block_device.h +++ b/kernel/driver/disk/block_device.h @@ -8,7 +8,7 @@ struct block_device_operation long (*open)(); long (*close)(); long (*ioctl)(long cmd, long arg); - long (*transfer)(long cmd, ul LBA_start, ul count, uchar* buffer); + long (*transfer)(long cmd, ul LBA_start, ul count, uint64_t buffer, uint8_t arg0, uint8_t arg1); }; /** @@ -18,10 +18,12 @@ struct block_device_operation struct block_device_request_packet { uchar cmd; - uint32_t LBA_start; + uint64_t LBA_start; uint32_t count; - uchar *buffer; + uint64_t buffer_vaddr; + uint8_t ahci_ctrl_num; // ahci控制器号, 默认应为0 + uint8_t port_num; // ahci的设备端口号 void (*end_handler)(ul num, ul arg); struct List list; @@ -34,6 +36,6 @@ struct block_device_request_packet struct block_device_request_queue { struct List queue_list; - struct block_device_request_packet * entry; + struct block_device_request_packet * in_service; // 正在请求的结点 ul request_count; }; \ No newline at end of file diff --git a/kernel/main.c b/kernel/main.c index d621408b..c136692c 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -167,7 +167,7 @@ void system_initialize() cpu_init(); //ps2_keyboard_init(); //ps2_mouse_init(); - ata_init(); + //ata_init(); pci_init(); ahci_init(); // test_slab(); @@ -182,7 +182,18 @@ void Start_Kernel(void) { system_initialize(); + + /* + uint64_t buf[100]; + ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, 0, 1, (uint64_t)&buf, 0, 0); + kdebug("buf[0]=%#010lx",(uint32_t)buf[0]); + buf[0] = 0xffd3; + ahci_operation.transfer(ATA_CMD_WRITE_DMA_EXT, 0, 1, (uint64_t)&buf, 0, 0); + + ahci_operation.transfer(ATA_CMD_READ_DMA_EXT, 0, 1, (uint64_t)&buf, 0, 0); + kdebug("buf[0]=%#010lx",(uint32_t)buf[0]); + */ // show_welcome(); // test_mm();