From 88d981e8325ea91ca6ca21cdba3c73308fe84541 Mon Sep 17 00:00:00 2001 From: Minep Date: Thu, 7 Jul 2022 14:12:53 +0100 Subject: [PATCH] feat: probe more device info feat: add port reset support fix: command is executed as CHS mode instead of LBA fix: delivery of MSI --- lunaix-os/config/make-debug-tool | 1 + lunaix-os/hal/ahci/ahci.c | 44 +++++++++++++++++++++++++------ lunaix-os/hal/ahci/ata.c | 11 +++++++- lunaix-os/hal/ahci/utils.c | 6 +++++ lunaix-os/hal/pci.c | 2 +- lunaix-os/includes/hal/ahci/hba.h | 3 +++ lunaix-os/includes/lunaix/spike.h | 2 +- lunaix-os/kernel/proc0.c | 8 +++--- 8 files changed, 62 insertions(+), 15 deletions(-) diff --git a/lunaix-os/config/make-debug-tool b/lunaix-os/config/make-debug-tool index 8d4e13d..2376ede 100644 --- a/lunaix-os/config/make-debug-tool +++ b/lunaix-os/config/make-debug-tool @@ -7,6 +7,7 @@ QEMU_OPTIONS := -s -S -m 1G \ -machine q35 \ -no-shutdown \ -d cpu_reset \ + -d trace:ide_dma_cb \ -drive id=disk,file="machine/disk0.vdi",if=none \ -device ahci,id=ahci \ -device ide-hd,drive=disk,bus=ahci.0 \ diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c index 31e9725..0907664 100644 --- a/lunaix-os/hal/ahci/ahci.c +++ b/lunaix-os/hal/ahci/ahci.c @@ -26,6 +26,8 @@ #define HBA_FIS_SIZE 256 #define HBA_CLB_SIZE 1024 +// #define DO_HBA_FULL_RESET + LOG_MODULE("AHCI") static struct ahci_hba hba; @@ -54,6 +56,22 @@ ahci_get_port(unsigned int index) return hba.ports[index]; } +void +__hba_reset_port(hba_reg_t* port_reg) +{ + // 根据:SATA-AHCI spec section 10.4.2 描述的端口重置流程 + port_reg[HBA_RPxCMD] &= ~HBA_PxCMD_ST; + port_reg[HBA_RPxCMD] &= ~HBA_PxCMD_FRE; + int cnt = wait_until_expire(!(port_reg[HBA_RPxCMD] & HBA_PxCMD_CR), 500000); + if (cnt) { + return; + } + // 如果port未响应,则继续执行重置 + port_reg[HBA_RPxSCTL] = (port_reg[HBA_RPxSCTL] & ~0xf) | 1; + io_delay(100000); //等待至少一毫秒,差不多就行了 + port_reg[HBA_RPxSCTL] &= ~0xf; +} + void ahci_init() { @@ -78,9 +96,11 @@ ahci_init() hba.base = (hba_reg_t*)ioremap(PCI_BAR_ADDR_MM(bar6), size); +#ifdef DO_HBA_FULL_RESET // 重置HBA hba.base[HBA_RGHC] |= HBA_RGHC_RESET; wait_until(!(hba.base[HBA_RGHC] & HBA_RGHC_RESET)); +#endif // 启用AHCI工作模式,启用中断 hba.base[HBA_RGHC] |= HBA_RGHC_ACHI_ENABLE; @@ -108,6 +128,10 @@ ahci_init() hba_reg_t* port_regs = (hba_reg_t*)(&hba.base[HBA_RPBASE + i * HBA_RPSIZE]); +#ifndef DO_HBA_FULL_RESET + __hba_reset_port(port_regs); +#endif + if (!clbp) { // 每页最多4个命令队列 clb_pa = pmm_alloc_page(KERNEL_PID, PP_FGLOCKED); @@ -136,19 +160,20 @@ ahci_init() // 需要通过全部置位去清空这些寄存器(相当的奇怪……) port_regs[HBA_RPxSERR] = -1; - port_regs[HBA_RPxIE] |= (HBA_PxINTR_DMA); port_regs[HBA_RPxIE] |= (HBA_PxINTR_D2HR); hba.ports[i] = port; - if (HBA_RPxSSTS_IF(port->ssts)) { - wait_until(!(port_regs[HBA_RPxCMD] & HBA_PxCMD_CR)); - port_regs[HBA_RPxCMD] |= HBA_PxCMD_FRE; - port_regs[HBA_RPxCMD] |= HBA_PxCMD_ST; + if (!HBA_RPxSSTS_IF(port->ssts)) { + continue; + } + + wait_until(!(port_regs[HBA_RPxCMD] & HBA_PxCMD_CR)); + port_regs[HBA_RPxCMD] |= HBA_PxCMD_FRE; + port_regs[HBA_RPxCMD] |= HBA_PxCMD_ST; - if (!ahci_init_device(port)) { - kprintf(KERROR "fail to init device"); - } + if (!ahci_init_device(port)) { + kprintf(KERROR "fail to init device"); } } } @@ -197,6 +222,9 @@ ahci_list_device() kprintf("\t\t capacity: %d KiB\n", (dev_info->max_lba * dev_info->block_size) >> 10); kprintf("\t\t block size: %dB\n", dev_info->block_size); + kprintf("\t\t block/sector: %d\n", dev_info->block_per_sec); + kprintf("\t\t alignment: %dB\n", dev_info->alignment_offset); + kprintf("\t\t capabilities: %x\n", dev_info->capabilities); kprintf("\t\t model: %s\n", &dev_info->model); kprintf("\t\t serial: %s\n", &dev_info->serial_num); } diff --git a/lunaix-os/hal/ahci/ata.c b/lunaix-os/hal/ahci/ata.c index 91863fd..486d69d 100644 --- a/lunaix-os/hal/ahci/ata.c +++ b/lunaix-os/hal/ahci/ata.c @@ -36,10 +36,19 @@ __sata_buffer_io(struct hba_port* port, // 如果该设备支持48位LBA寻址 sata_create_fis( fis, write ? ATA_WRITE_DMA_EXT : ATA_READ_DMA_EXT, lba, count); - fis->dev = (1 << 6) * (!write); } else { sata_create_fis(fis, write ? ATA_WRITE_DMA : ATA_READ_DMA, lba, count); } + /* + 确保我们使用的是LBA寻址模式 + 注意:在ACS-3中(甚至在ACS-4),只有在(READ/WRITE)_DMA_EXT指令中明确注明了需要将这一位置位 + 而并没有在(READ/WRITE)_DMA注明。 + 但是这在ACS-2中是有的!于是这也就导致了先前的测试中,LBA=0根本无法访问,因为此时 + 的访问模式是在CHS下,也就是说LBA=0 => Sector=0,是非法的。 + 所以,我猜测,这要么是QEMU/VirtualBox根据ACS-2来编写的AHCI模拟, + 要么是标准出错了(毕竟是working draft) + */ + fis->dev = (1 << 6); int retries = 0; diff --git a/lunaix-os/hal/ahci/utils.c b/lunaix-os/hal/ahci/utils.c index 3b1fbcb..e101efd 100644 --- a/lunaix-os/hal/ahci/utils.c +++ b/lunaix-os/hal/ahci/utils.c @@ -9,6 +9,9 @@ #define IDDEV_OFFSERIALNUM 10 #define IDDEV_OFFMODELNUM 27 #define IDDEV_OFFADDSUPPORT 69 +#define IDDEV_OFFALIGN 209 +#define IDDEV_OFFLPP 106 +#define IDDEV_OFFCAPABILITIES 49 void ahci_parse_dev_info(struct hba_device* dev_info, uint16_t* data) @@ -17,6 +20,9 @@ ahci_parse_dev_info(struct hba_device* dev_info, uint16_t* data) dev_info->block_size = *((uint32_t*)(data + IDDEV_OFFLSECSIZE)); dev_info->cbd_size = (*data & 0x3) ? 16 : 12; dev_info->wwn = *(uint64_t*)(data + IDDEV_OFFWWN); + dev_info->block_per_sec = 1 << (*(data + IDDEV_OFFLPP) & 0xf); + dev_info->alignment_offset = *(data + IDDEV_OFFALIGN) & 0x3fff; + dev_info->capabilities = *((uint32_t*)(data + IDDEV_OFFCAPABILITIES)); if (!dev_info->block_size) { dev_info->block_size = 512; diff --git a/lunaix-os/hal/pci.c b/lunaix-os/hal/pci.c index c3771d5..4bf4c56 100644 --- a/lunaix-os/hal/pci.c +++ b/lunaix-os/hal/pci.c @@ -174,7 +174,7 @@ void pci_setup_msi(struct pci_device* device, int vector) { // Dest: APIC#0, Physical Destination, No redirection - uint32_t msi_addr = (__APIC_BASE_PADDR | 0x8); + uint32_t msi_addr = (__APIC_BASE_PADDR); // Edge trigger, Fixed delivery uint32_t msi_data = vector; diff --git a/lunaix-os/includes/hal/ahci/hba.h b/lunaix-os/includes/hal/ahci/hba.h index 19f76cd..9dc7071 100644 --- a/lunaix-os/includes/hal/ahci/hba.h +++ b/lunaix-os/includes/hal/ahci/hba.h @@ -101,6 +101,9 @@ struct hba_device uint8_t cbd_size; uint8_t last_error; uint8_t last_status; + uint32_t alignment_offset; + uint32_t block_per_sec; + uint32_t capabilities; struct { diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index 6f91924..777a457 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -57,7 +57,7 @@ panick(const char* msg); #define wait_until_expire(cond, max) \ ({ \ unsigned int __wcounter__ = (max); \ - while (!(cond) && __wcounter__-- > 0) \ + while (!(cond) && __wcounter__-- > 1) \ ; \ __wcounter__; \ }) diff --git a/lunaix-os/kernel/proc0.c b/lunaix-os/kernel/proc0.c index b9a2470..be7d468 100644 --- a/lunaix-os/kernel/proc0.c +++ b/lunaix-os/kernel/proc0.c @@ -119,14 +119,14 @@ void __test_disk_io() { struct hba_port* port = ahci_get_port(0); - char* buffer = valloc_dma(port->device->block_size); + char* buffer = vcalloc_dma(port->device->block_size); strcpy(buffer, test_sequence); kprintf("WRITE: %s\n", buffer); int result; - // 写入第一扇区 + // 写入第一扇区 (LBA=0) result = - port->device->ops.write_buffer(port, 1, buffer, port->device->block_size); + port->device->ops.write_buffer(port, 0, buffer, port->device->block_size); if (!result) { kprintf(KWARN "fail to write: %x\n", port->device->last_error); } @@ -135,7 +135,7 @@ __test_disk_io() // 读出我们刚刚写的内容! result = - port->device->ops.read_buffer(port, 1, buffer, port->device->block_size); + port->device->ops.read_buffer(port, 0, buffer, port->device->block_size); kprintf(KDEBUG "%x, %x\n", port->regs[HBA_RPxIS], port->regs[HBA_RPxTFD]); if (!result) { kprintf(KWARN "fail to read: %x\n", port->device->last_error); -- 2.27.0