From 839da03f6ebe838d780e52190318d4c3048990f1 Mon Sep 17 00:00:00 2001 From: Minep Date: Wed, 29 Jun 2022 15:07:03 +0100 Subject: [PATCH] feat: spec-compliant AHCI HBA initialization feat: detect device presence on hba port fix: ioremap will disable caching on all mapped page. refactor: releasing the reclaimable page when unlocking memory --- lunaix-os/hal/ahci.c | 55 ------------ lunaix-os/hal/ahci/ahci.c | 120 +++++++++++++++++++++++++++ lunaix-os/includes/hal/ahci.h | 35 +++++++- lunaix-os/includes/hal/pci.h | 6 ++ lunaix-os/includes/lunaix/mm/vmm.h | 2 +- lunaix-os/kernel/mm/mmio.c | 2 +- lunaix-os/kernel/mm/vmap.c | 2 +- lunaix-os/kernel/peripheral/ps2kbd.c | 8 +- lunaix-os/kernel/proc0.c | 6 ++ 9 files changed, 171 insertions(+), 65 deletions(-) delete mode 100644 lunaix-os/hal/ahci.c create mode 100644 lunaix-os/hal/ahci/ahci.c diff --git a/lunaix-os/hal/ahci.c b/lunaix-os/hal/ahci.c deleted file mode 100644 index fa87fd3..0000000 --- a/lunaix-os/hal/ahci.c +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file ahci.c - * @author Lunaixsky (zelong56@gmail.com) - * @brief A software implementation of Serial ATA AHCI 1.3.1 Specification - * @version 0.1 - * @date 2022-06-28 - * - * @copyright Copyright (c) 2022 - * - */ -#include -#include -#include -#include -#include - -LOG_MODULE("AHCI") - -static struct ahci_hba hba; - -void -ahci_init() -{ - struct pci_device* ahci_dev = pci_get_device_by_class(0x10601); - assert_msg(ahci_dev, "AHCI: Not found."); - - uintptr_t bar6, size; - size = pci_bar_sizing(ahci_dev, &bar6, 6); - assert_msg(bar6 && PCI_BAR_MMIO(bar6), "AHCI: BAR#6 is not MMIO."); - - hba.base = (hba_reg_t*)ioremap(PCI_BAR_ADDR_MM(bar6), size); - - // Enable AHCI, Enable interrupt generation. - hba.base[HBA_RGHC] |= 0x80000002; - - // As per section 3.1.1, this is 0 based value. - hba.ports_num = (hba.base[HBA_RCAP] & 0x1f) + 1; - hba.version = hba.base[HBA_RVER]; - - kprintf(KINFO "Version: %x; Ports: %d\n", hba.version, hba.ports_num); - - hba_reg_t pmap = hba.base[HBA_RPI]; - for (size_t i = 0; i < 32; i++, pmap = pmap >> 1) { - if (!(pmap & 0x1)) { - continue; - } - hba.ports[i] = (hba_reg_t*)(&hba.base[HBA_RPBASE] + i); - kprintf("\t Port#%d, clb: %p, fis: %p\n", - i + 1, - hba.ports[i][HBA_RPxCLB], - hba.ports[i][HBA_RPxFB]); - - // TODO: (?) Rebasing each port's command list and FIS - } -} \ No newline at end of file diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c new file mode 100644 index 0000000..c5989fb --- /dev/null +++ b/lunaix-os/hal/ahci/ahci.c @@ -0,0 +1,120 @@ +/** + * @file ahci.c + * @author Lunaixsky (zelong56@gmail.com) + * @brief A software implementation of Serial ATA AHCI 1.3.1 Specification + * @version 0.1 + * @date 2022-06-28 + * + * @copyright Copyright (c) 2022 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define HBA_FIS_SIZE 256 +#define HBA_CLB_SIZE 1024 + +LOG_MODULE("AHCI") + +static struct ahci_hba hba; + +void +ahci_init() +{ + struct pci_device* ahci_dev = pci_get_device_by_class(AHCI_HBA_CLASS); + assert_msg(ahci_dev, "AHCI: Not found."); + + uintptr_t bar6, size; + size = pci_bar_sizing(ahci_dev, &bar6, 6); + assert_msg(bar6 && PCI_BAR_MMIO(bar6), "AHCI: BAR#6 is not MMIO."); + + pci_reg_t cmd = pci_read_cspace(ahci_dev->cspace_base, PCI_REG_STATUS_CMD); + + // 禁用传统中断(因为我们使用MSI),启用MMIO访问,允许PCI设备间访问 + cmd |= (PCI_RCMD_MM_ACCESS | PCI_RCMD_DISABLE_INTR | PCI_RCMD_BUS_MASTER); + + pci_write_cspace(ahci_dev->cspace_base, PCI_REG_STATUS_CMD, cmd); + + hba.base = (hba_reg_t*)ioremap(PCI_BAR_ADDR_MM(bar6), size); + + // 重置HBA + hba.base[HBA_RGHC] |= HBA_RGHC_RESET; + wait_until(!(hba.base[HBA_RGHC] & HBA_RGHC_RESET)); + + // 启用AHCI工作模式,启用中断 + hba.base[HBA_RGHC] |= (HBA_RGHC_ACHI_ENABLE | HBA_RGHC_INTR_ENABLE); + + // As per section 3.1.1, this is 0 based value. + hba_reg_t cap = hba.base[HBA_RCAP]; + hba.ports_num = (cap & 0x1f) + 1; // CAP.PI + hba.cmd_slots = (cap >> 8) & 0x1f; // CAP.NCS + hba.version = hba.base[HBA_RVER]; + + /* ------ HBA端口配置 ------ */ + hba_reg_t pmap = hba.base[HBA_RPI]; + uintptr_t clb_pg_addr, fis_pg_addr, clb_pa, fis_pa; + for (size_t i = 0, fisp = 0, clbp = 0; i < 32; + i++, pmap >>= 1, fisp = (fisp + 1) % 16, clbp = (clbp + 1) % 4) { + if (!(pmap & 0x1)) { + continue; + } + + struct ahci_port* port = + (struct ahci_port*)lxmalloc(sizeof(struct ahci_port)); + hba_reg_t* port_regs = + (hba_reg_t*)(&hba.base[HBA_RPBASE + i * HBA_RPSIZE]); + + if (!clbp) { + // 每页最多4个命令队列 + clb_pa = pmm_alloc_page(KERNEL_PID, PP_FGLOCKED); + clb_pg_addr = ioremap(clb_pa, 0x1000); + memset(clb_pg_addr, 0, 0x1000); + } + if (!fisp) { + // 每页最多16个FIS + fis_pa = pmm_alloc_page(KERNEL_PID, PP_FGLOCKED); + fis_pg_addr = ioremap(fis_pa, 0x1000); + memset(fis_pg_addr, 0, 0x1000); + } + + /* 重定向CLB与FIS */ + port_regs[HBA_RPxCLB] = clb_pa + clbp * HBA_CLB_SIZE; + port_regs[HBA_RPxFB] = fis_pa + fisp * HBA_FIS_SIZE; + + *port = + (struct ahci_port){ .regs = port_regs, + .ssts = port_regs[HBA_RPxSSTS], + .cmdlstv = clb_pg_addr + clbp * HBA_CLB_SIZE, + .fisv = fis_pg_addr + fisp * HBA_FIS_SIZE }; + + /* 初始化端口,并置于就绪状态 */ + port_regs[HBA_RPxCI] = 0; + port_regs[HBA_RPxIE] |= (HBA_PxINTR_DMA | HBA_PxINTR_D2HR); + port_regs[HBA_RPxCMD] |= (HBA_PxCMD_FRE | HBA_PxCMD_ST); + + hba.ports[i] = port; + } +} + +char sata_ifs[][20] = { "Not detected", + "SATA I (1.5Gbps)", + "SATA II (3.0Gbps)", + "SATA III (6.0Gbps)" }; + +void +ahci_list_device() +{ + kprintf(KINFO "Version: %x; Ports: %d\n", hba.version, hba.ports_num); + for (size_t i = 0; i < 32; i++) { + struct ahci_port* port = hba.ports[i]; + if (!port) + continue; + kprintf("\t Port %d: %s\n", i, &sata_ifs[HBA_RPxSSTS_IF(port->ssts)]); + } +} \ No newline at end of file diff --git a/lunaix-os/includes/hal/ahci.h b/lunaix-os/includes/hal/ahci.h index 438fa5c..dc30ca8 100644 --- a/lunaix-os/includes/hal/ahci.h +++ b/lunaix-os/includes/hal/ahci.h @@ -10,6 +10,8 @@ * All registers offset are 0 based index of a DWORD array */ +#define AHCI_HBA_CLASS 0x10601 + #define HBA_RCAP 0 #define HBA_RGHC 1 #define HBA_RIS 2 @@ -17,6 +19,7 @@ #define HBA_RVER 4 #define HBA_RPBASE (0x40) +#define HBA_RPSIZE (0x80 >> 2) #define HBA_RPxCLB 0 #define HBA_RPxFB 2 #define HBA_RPxIS 4 @@ -32,18 +35,46 @@ #define HBA_RPxSNTF 15 #define HBA_RPxFBS 16 +#define HBA_PxCMD_FRE (1 << 4) +#define HBA_PxCMD_ST (1) +#define HBA_PxINTR_DMA (1 << 2) +#define HBA_PxINTR_D2HR (1) + +#define HBA_RGHC_ACHI_ENABLE (1 << 31) +#define HBA_RGHC_INTR_ENABLE (1 << 1) +#define HBA_RGHC_RESET 1 + +#define HBA_RPxSSTS_PWR(x) (((x) >> 8) & 0xf) +#define HBA_RPxSSTS_IF(x) (((x) >> 4) & 0xf) +#define HBA_RPxSSTS_PHYSTATE(x) ((x)&0xf) + typedef unsigned int hba_reg_t; +struct ahci_port +{ + hba_reg_t* regs; + unsigned int ssts; + void* cmdlstv; + void* fisv; +}; + struct ahci_hba { volatile hba_reg_t* base; unsigned int ports_num; - unsigned int port_map; + unsigned int cmd_slots; unsigned int version; - hba_reg_t* ports[32]; + struct ahci_port* ports[32]; }; +/** + * @brief 初始化AHCI与HBA + * + */ void ahci_init(); +void +ahci_list_device(); + #endif /* __LUNAIX_AHCI_H */ diff --git a/lunaix-os/includes/hal/pci.h b/lunaix-os/includes/hal/pci.h index 639a12c..b31352b 100644 --- a/lunaix-os/includes/hal/pci.h +++ b/lunaix-os/includes/hal/pci.h @@ -36,6 +36,12 @@ #define PCI_MSI_ADDR(msi_base) ((msi_base) + 4) #define PCI_MSI_DATA(msi_base) ((msi_base) + 8) +#define PCI_RCMD_DISABLE_INTR (1 << 10) +#define PCI_RCMD_FAST_B2B (1 << 9) +#define PCI_RCMD_BUS_MASTER (1 << 2) +#define PCI_RCMD_MM_ACCESS (1 << 1) +#define PCI_RCMD_IO_ACCESS 1 + #define PCI_ADDRESS(bus, dev, funct) \ (((bus)&0xff) << 16) | (((dev)&0xff) << 11) | (((funct)&0xff) << 8) | \ 0x80000000 diff --git a/lunaix-os/includes/lunaix/mm/vmm.h b/lunaix-os/includes/lunaix/mm/vmm.h index db6e058..98f5763 100644 --- a/lunaix-os/includes/lunaix/mm/vmm.h +++ b/lunaix-os/includes/lunaix/mm/vmm.h @@ -117,6 +117,6 @@ vmm_next_free(uintptr_t start, int options); * @return void* */ void* -vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr, uint32_t pattr); +vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr); #endif /* __LUNAIX_VMM_H */ diff --git a/lunaix-os/kernel/mm/mmio.c b/lunaix-os/kernel/mm/mmio.c index f6d5368..5e0d01e 100644 --- a/lunaix-os/kernel/mm/mmio.c +++ b/lunaix-os/kernel/mm/mmio.c @@ -5,7 +5,7 @@ void* ioremap(uintptr_t paddr, uint32_t size) { - return vmm_vmap(paddr, size, PG_PREM_RW, PP_FGPERSIST); + return vmm_vmap(paddr, size, PG_PREM_RW | PG_DISABLE_CACHE); } void* diff --git a/lunaix-os/kernel/mm/vmap.c b/lunaix-os/kernel/mm/vmap.c index 0c10610..5df524d 100644 --- a/lunaix-os/kernel/mm/vmap.c +++ b/lunaix-os/kernel/mm/vmap.c @@ -8,7 +8,7 @@ static uintptr_t start = VMAP_START; void* -vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr, pp_attr_t pattr) +vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr) { // next fit assert_msg((paddr & 0xfff) == 0, "vmap: bad alignment"); diff --git a/lunaix-os/kernel/peripheral/ps2kbd.c b/lunaix-os/kernel/peripheral/ps2kbd.c index 72f5d1f..6d27b10 100644 --- a/lunaix-os/kernel/peripheral/ps2kbd.c +++ b/lunaix-os/kernel/peripheral/ps2kbd.c @@ -124,11 +124,9 @@ ps2_kbd_init() * 需要注意:Bochs 和 QEMU 使用的是ACPI v1,而非 v2 * (virtualbox好像是v4) * - * (2022/6/28) - * QEMU似乎在 Q35 + ICH9 支持了 ACPI - * v2。但是对于IAPC_BOOT_ARCH的设置还是 停留在ACPI - * v1的时代。IAPC_ARCH_8042没有被正确的设置。这是一个今年的bug,好像还未修复 - * 参考:https://lore.kernel.org/all/20220304115257.1816983-1-ani@anisinha.ca/T/ + * (2022/6/29) + * QEMU在7.0.0版本中,修复了FADT::IAPC_BOOT无法正确提供关于i8042的信息的bug + * https://wiki.qemu.org/ChangeLog/7.0#ACPI_.2F_SMBIOS * * 请看Bochs的bios源码(QEMU的BIOS其实是照抄bochs的,所以也是一个德行。。): * https://bochs.sourceforge.io/cgi-bin/lxr/source/bios/rombios32.c#L1314 diff --git a/lunaix-os/kernel/proc0.c b/lunaix-os/kernel/proc0.c index d195679..3a6ea62 100644 --- a/lunaix-os/kernel/proc0.c +++ b/lunaix-os/kernel/proc0.c @@ -124,6 +124,7 @@ init_platform() pci_init(); ahci_init(); pci_print_device(); + ahci_list_device(); syscall_install(); @@ -174,6 +175,8 @@ __do_reserved_memory(int unlock) break; } vmm_set_mapping(PD_REFERENCED, _pa, _pa, PG_PREM_R, VMAP_NULL); + pmm_mark_page_occupied( + KERNEL_PID, _pa >> PG_SIZE_BITS, PP_FGLOCKED); } // Save the progress for later unmapping. mmaps[i].len_low = j * PG_SIZE; @@ -181,6 +184,9 @@ __do_reserved_memory(int unlock) for (; j < pg_num; j++) { uintptr_t _pa = pa + (j << PG_SIZE_BITS); vmm_del_mapping(PD_REFERENCED, _pa); + if (mmap.type == MULTIBOOT_MEMORY_ACPI_RECLAIMABLE) { + pmm_mark_page_free(_pa >> PG_SIZE_BITS); + } } } } -- 2.27.0