From 43c43c058ededea929645fef68d15820eed1f5e9 Mon Sep 17 00:00:00 2001 From: Minep Date: Thu, 10 Nov 2022 18:33:40 +0000 Subject: [PATCH] feat: (ahci) support multiple AHCI controller feat: (pci) pci device driver auto-binding refactor: (isrm) change the interrupt vector type to int fix: (waitq) mitigation of possible race condition in pwait fix: (sched) expand stack size of dummy process for allowance in the using of kprintf refactor: (kinit) reserve the higher half space as earlier as possible. --- lunaix-os/hal/ahci/ahci.c | 113 +++++++++------------------ lunaix-os/hal/pci.c | 71 ++++++++++++++--- lunaix-os/includes/hal/ahci/ahci.h | 16 ++-- lunaix-os/includes/hal/ahci/hba.h | 4 + lunaix-os/includes/hal/pci.h | 30 +++++++ lunaix-os/includes/lunaix/isrm.h | 16 ++-- lunaix-os/kernel/asm/x86/i386_isrm.c | 22 +++--- lunaix-os/kernel/ds/waitq.c | 6 ++ lunaix-os/kernel/k_init.c | 5 ++ lunaix-os/kernel/proc0.c | 8 +- lunaix-os/kernel/process/sched.c | 34 ++++---- 11 files changed, 191 insertions(+), 134 deletions(-) diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c index f6f2718..b9bca95 100644 --- a/lunaix-os/hal/ahci/ahci.c +++ b/lunaix-os/hal/ahci/ahci.c @@ -27,13 +27,13 @@ #define HBA_FIS_SIZE 256 #define HBA_CLB_SIZE 1024 -#define HBA_MY_IE (HBA_PxINTR_DHR | HBA_PxINTR_TFEE) +#define HBA_MY_IE (HBA_PxINTR_DHR | HBA_PxINTR_TFEE | HBA_PxINTR_OFE) // #define DO_HBA_FULL_RESET LOG_MODULE("AHCI") -struct ahci_hba hba; +struct llist_header ahcis; static char sata_ifs[][20] = { "Not detected", "SATA I (1.5Gbps)", @@ -58,20 +58,8 @@ achi_register_ops(struct hba_port* port); void ahci_register_device(struct hba_device* hbadev); -unsigned int -ahci_get_port_usage() -{ - return hba.ports_bmp; -} - -struct hba_port* -ahci_get_port(unsigned int index) -{ - if (index >= 32) { - return 0; - } - return hba.ports[index]; -} +void* +ahci_driver_init(struct pci_device* ahci_dev); void __hba_reset_port(hba_reg_t* port_reg) @@ -92,9 +80,13 @@ __hba_reset_port(hba_reg_t* port_reg) void ahci_init() { - struct pci_device* ahci_dev = pci_get_device_by_class(AHCI_HBA_CLASS); - assert_msg(ahci_dev, "AHCI: Not found."); + llist_init_head(&ahcis); + pci_add_driver("Serial ATA AHCI", AHCI_HBA_CLASS, 0, 0, ahci_driver_init); +} +void* +ahci_driver_init(struct pci_device* ahci_dev) +{ struct pci_base_addr* bar6 = &ahci_dev->bar[5]; assert_msg(bar6->type & BAR_TYPE_MMIO, "AHCI: BAR#6 is not MMIO."); @@ -105,30 +97,35 @@ ahci_init() pci_write_cspace(ahci_dev->cspace_base, PCI_REG_STATUS_CMD, cmd); - pci_setup_msi(ahci_dev, isrm_ivexalloc(__ahci_hba_isr)); + int iv = isrm_ivexalloc(__ahci_hba_isr); + pci_setup_msi(ahci_dev, iv); + + struct ahci_driver* ahci_drv = vzalloc(sizeof(*ahci_drv)); + struct ahci_hba* hba = &ahci_drv->hba; + ahci_drv->id = iv; - memset(&hba, 0, sizeof(hba)); + llist_append(&ahcis, &ahci_drv->ahci_drvs); - hba.base = (hba_reg_t*)ioremap(bar6->start, bar6->size); + hba->base = (hba_reg_t*)ioremap(bar6->start, bar6->size); #ifdef DO_HBA_FULL_RESET // 重置HBA - hba.base[HBA_RGHC] |= HBA_RGHC_RESET; - wait_until(!(hba.base[HBA_RGHC] & HBA_RGHC_RESET)); + 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; - hba.base[HBA_RGHC] |= HBA_RGHC_INTR_ENABLE; + hba->base[HBA_RGHC] |= HBA_RGHC_ACHI_ENABLE; + hba->base[HBA_RGHC] |= HBA_RGHC_INTR_ENABLE; // As per section 3.1.1, this is 0 based value. - hba_reg_t cap = hba.base[HBA_RCAP]; - hba_reg_t pmap = hba.base[HBA_RPI]; + hba_reg_t cap = hba->base[HBA_RCAP]; + hba_reg_t pmap = hba->base[HBA_RPI]; - hba.ports_num = (cap & 0x1f) + 1; // CAP.PI - hba.cmd_slots = (cap >> 8) & 0x1f; // CAP.NCS - hba.version = hba.base[HBA_RVER]; - hba.ports_bmp = pmap; + hba->ports_num = (cap & 0x1f) + 1; // CAP.PI + hba->cmd_slots = (cap >> 8) & 0x1f; // CAP.NCS + hba->version = hba->base[HBA_RVER]; + hba->ports_bmp = pmap; /* ------ HBA端口配置 ------ */ uintptr_t clb_pg_addr, fis_pg_addr, clb_pa, fis_pa; @@ -141,7 +138,7 @@ ahci_init() struct hba_port* port = (struct hba_port*)valloc(sizeof(struct hba_port)); hba_reg_t* port_regs = - (hba_reg_t*)(&hba.base[HBA_RPBASE + i * HBA_RPSIZE]); + (hba_reg_t*)(&hba->base[HBA_RPBASE + i * HBA_RPSIZE]); #ifndef DO_HBA_FULL_RESET __hba_reset_port(port_regs); @@ -167,14 +164,15 @@ ahci_init() *port = (struct hba_port){ .regs = port_regs, .ssts = port_regs[HBA_RPxSSTS], .cmdlst = clb_pg_addr + clbp * HBA_CLB_SIZE, - .fis = fis_pg_addr + fisp * HBA_FIS_SIZE }; + .fis = fis_pg_addr + fisp * HBA_FIS_SIZE, + .hba = hba }; /* 初始化端口,并置于就绪状态 */ port_regs[HBA_RPxCI] = 0; hba_clear_reg(port_regs[HBA_RPxSERR]); - hba.ports[i] = port; + hba->ports[i] = port; if (!HBA_RPxSSTS_IF(port->ssts)) { continue; @@ -198,6 +196,8 @@ ahci_init() ahci_register_device(hbadev); } + + return ahci_drv; } void @@ -212,46 +212,6 @@ ahci_register_device(struct hba_device* hbadev) block_mount(bdev, ahci_fsexport); } -void -ahci_list_device() -{ - kprintf(KINFO "Version: %x; Ports: %d; Slot: %d\n", - hba.version, - hba.ports_num, - hba.cmd_slots); - struct hba_port* port; - for (size_t i = 0; i < 32; i++) { - port = hba.ports[i]; - - // 愚蠢的gcc似乎认为 struct hba_port* 不可能为空 - // 所以将这个非常关键的if给优化掉了。 - // 这里将指针强制转换为整数,欺骗gcc :) - if ((uintptr_t)port == 0) { - continue; - } - - int device_state = HBA_RPxSSTS_IF(port->ssts); - - kprintf("\t Port %d: %s (%x)\n", - i, - &sata_ifs[device_state], - port->device->flags); - - struct hba_device* dev_info = port->device; - if (!device_state || !dev_info) { - continue; - } - 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); - } -} - int __get_free_slot(struct hba_port* port) { @@ -259,9 +219,9 @@ __get_free_slot(struct hba_port* port) hba_reg_t pxci = port->regs[HBA_RPxCI]; hba_reg_t free_bmp = pxsact | pxci; uint32_t i = 0; - for (; i <= hba.cmd_slots && (free_bmp & 0x1); i++, free_bmp >>= 1) + for (; i <= port->hba->cmd_slots && (free_bmp & 0x1); i++, free_bmp >>= 1) ; - return i | -(i > hba.cmd_slots); + return i | -(i > port->hba->cmd_slots); } void @@ -358,6 +318,7 @@ ahci_init_device(struct hba_port* port) port->device = vzalloc(sizeof(struct hba_device)); port->device->port = port; + port->device->hba = port->hba; // 在命令表中构建命令FIS struct sata_reg_fis* cmd_fis = (struct sata_reg_fis*)cmd_table->command_fis; diff --git a/lunaix-os/hal/pci.c b/lunaix-os/hal/pci.c index 229335c..cb7cfe7 100644 --- a/lunaix-os/hal/pci.c +++ b/lunaix-os/hal/pci.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +19,8 @@ LOG_MODULE("PCI") -static struct llist_header pci_devices; +static DEFINE_LLIST(pci_devices); +static DEFINE_LLIST(pci_drivers); void pci_probe_msi_info(struct pci_device* device); @@ -62,17 +64,27 @@ pci_probe_device(int bus, int dev, int funct) .device_info = reg1, .intr_info = intr }; - kprintf("dev.%d:%d:%d %x:%x\n", - bus, - dev, - funct, - PCI_DEV_VENDOR(reg1), - PCI_DEV_DEVID(reg1)); - pci_probe_msi_info(device); pci_probe_bar_info(device); llist_append(&pci_devices, &device->dev_chain); + + if (!pci_bind_driver(device)) { + kprintf(KWARN "dev.%d:%d:%d %x:%x unknown device\n", + bus, + dev, + funct, + PCI_DEV_VENDOR(reg1), + PCI_DEV_DEVID(reg1)); + } else { + kprintf("dev.%d:%d:%d %x:%x %s\n", + bus, + dev, + funct, + PCI_DEV_VENDOR(reg1), + PCI_DEV_DEVID(reg1), + device->driver.type->name); + } } void @@ -308,10 +320,51 @@ pci_get_device_by_class(uint32_t class) return NULL; } +void +pci_add_driver(const char* name, + u32_t class, + u32_t vendor, + u32_t devid, + pci_drv_init init) +{ + struct pci_driver* pci_drv = valloc(sizeof(*pci_drv)); + *pci_drv = (struct pci_driver){ .create_driver = init, + .dev_info = (vendor << 16) | devid, + .dev_class = class }; + if (name) { + strncpy(pci_drv->name, name, PCI_DRV_NAME_LEN); + } + + llist_append(&pci_drivers, &pci_drv->drivers); +} + +int +pci_bind_driver(struct pci_device* pci_dev) +{ + struct pci_driver *pos, *n; + llist_for_each(pos, n, &pci_drivers, drivers) + { + if (pos->dev_info) { + if (pos->dev_info == pci_dev->device_info) { + goto check_type; + } + continue; + } + check_type: + if (pos->dev_class) { + if (pos->dev_class == PCI_DEV_CLASS(pci_dev->class_info)) { + pci_dev->driver.type = pos; + pci_dev->driver.instance = pos->create_driver(pci_dev); + return 1; + } + } + } + return 0; +} + void pci_init() { - llist_init_head(&pci_devices); acpi_context* acpi = acpi_get_context(); assert_msg(acpi, "ACPI not initialized."); if (acpi->mcfg.alloc_num) { diff --git a/lunaix-os/includes/hal/ahci/ahci.h b/lunaix-os/includes/hal/ahci/ahci.h index ea63a9c..2ed135a 100644 --- a/lunaix-os/includes/hal/ahci/ahci.h +++ b/lunaix-os/includes/hal/ahci/ahci.h @@ -14,6 +14,13 @@ #define AHCI_HBA_CLASS 0x10601 +struct ahci_driver +{ + struct llist_header ahci_drvs; + struct ahci_hba hba; + int id; +}; + /** * @brief 初始化AHCI与HBA * @@ -21,15 +28,6 @@ void ahci_init(); -void -ahci_list_device(); - -unsigned int -ahci_get_port_usage(); - -struct hba_port* -ahci_get_port(unsigned int index); - void ahci_parse_dev_info(struct hba_device* dev_info, uint16_t* data); diff --git a/lunaix-os/includes/hal/ahci/hba.h b/lunaix-os/includes/hal/ahci/hba.h index c60536d..287f868 100644 --- a/lunaix-os/includes/hal/ahci/hba.h +++ b/lunaix-os/includes/hal/ahci/hba.h @@ -36,6 +36,7 @@ #define HBA_PxINTR_DHR (1) #define HBA_PxINTR_DPS (1 << 5) #define HBA_PxINTR_TFEE (1 << 30) +#define HBA_PxINTR_OFE (1 << 24) #define HBA_PxINTR_IFE (1 << 27) #define HBA_PxTFD_ERR (1) #define HBA_PxTFD_BSY (1 << 7) @@ -98,6 +99,7 @@ struct hba_cmdt #define HBA_DEV_FATAPI (1 << 1) struct hba_port; +struct ahci_hba; struct hba_device { @@ -119,6 +121,7 @@ struct hba_device uint32_t block_per_sec; uint32_t capabilities; struct hba_port* port; + struct ahci_hba* hba; struct { @@ -147,6 +150,7 @@ struct hba_port struct hba_cmd_context cmdctx; void* fis; struct hba_device* device; + struct ahci_hba* hba; }; struct ahci_hba diff --git a/lunaix-os/includes/hal/pci.h b/lunaix-os/includes/hal/pci.h index 95d5fb8..21952f2 100644 --- a/lunaix-os/includes/hal/pci.h +++ b/lunaix-os/includes/hal/pci.h @@ -3,6 +3,7 @@ #include #include +#include #define PCI_CONFIG_ADDR 0xcf8 #define PCI_CONFIG_DATA 0xcfc @@ -58,6 +59,9 @@ typedef unsigned int pci_reg_t; #define BAR_TYPE_MMIO 0x1 #define BAR_TYPE_CACHABLE 0x2 +#define PCI_DRV_NAME_LEN 32 + +struct pci_driver; struct pci_base_addr { @@ -74,9 +78,25 @@ struct pci_device uint32_t cspace_base; uint32_t msi_loc; uint16_t intr_info; + struct + { + struct pci_driver* type; + void* instance; + } driver; struct pci_base_addr bar[6]; }; +typedef void* (*pci_drv_init)(struct pci_device*); + +struct pci_driver +{ + struct llist_header drivers; + u32_t dev_info; + u32_t dev_class; + pci_drv_init create_driver; + char name[PCI_DRV_NAME_LEN]; +}; + // PCI Configuration Space (C-Space) r/w: // Refer to "PCI Local Bus Specification, Rev.3, Section 3.2.2.3.2" @@ -144,4 +164,14 @@ pci_bar_sizing(struct pci_device* dev, uint32_t* bar_out, uint32_t bar_num); void pci_setup_msi(struct pci_device* device, int vector); +void +pci_add_driver(const char* name, + u32_t class, + u32_t vendor, + u32_t devid, + pci_drv_init init); + +int +pci_bind_driver(struct pci_device* pci_dev); + #endif /* __LUNAIX_PCI_H */ diff --git a/lunaix-os/includes/lunaix/isrm.h b/lunaix-os/includes/lunaix/isrm.h index 32ba31d..afa8146 100644 --- a/lunaix-os/includes/lunaix/isrm.h +++ b/lunaix-os/includes/lunaix/isrm.h @@ -25,21 +25,21 @@ void isrm_init(); void -isrm_ivfree(uint32_t iv); +isrm_ivfree(int iv); -uint32_t +int isrm_ivosalloc(isr_cb handler); -uint32_t +int isrm_ivexalloc(isr_cb handler); -uint32_t -isrm_bindirq(uint32_t irq, isr_cb irq_handler); +int +isrm_bindirq(int irq, isr_cb irq_handler); -uint32_t -isrm_bindiv(uint32_t iv, isr_cb handler); +int +isrm_bindiv(int iv, isr_cb handler); isr_cb -isrm_get(uint32_t iv); +isrm_get(int iv); #endif /* __LUNAIX_ISRM_H */ diff --git a/lunaix-os/kernel/asm/x86/i386_isrm.c b/lunaix-os/kernel/asm/x86/i386_isrm.c index 0a26c3b..9c18637 100644 --- a/lunaix-os/kernel/asm/x86/i386_isrm.c +++ b/lunaix-os/kernel/asm/x86/i386_isrm.c @@ -25,7 +25,7 @@ isrm_init() } } -static inline uint32_t +static inline int __ivalloc_within(size_t a, size_t b, isr_cb handler) { a = (a - IV_BASE) / 8; @@ -39,27 +39,27 @@ __ivalloc_within(size_t a, size_t b, isr_cb handler) j++; } iv_bmp[i] |= 1 << j; - uint32_t iv = IV_BASE + i * 8 + j; + int iv = IV_BASE + i * 8 + j; handlers[iv] = handler ? handler : intr_routine_fallback; return iv; } return 0; } -uint32_t +int isrm_ivosalloc(isr_cb handler) { return __ivalloc_within(IV_BASE, IV_EX, handler); } -uint32_t +int isrm_ivexalloc(isr_cb handler) { return __ivalloc_within(IV_EX, IV_MAX, handler); } void -isrm_ivfree(uint32_t iv) +isrm_ivfree(int iv) { assert(iv < 256); if (iv >= IV_BASE) { @@ -68,10 +68,10 @@ isrm_ivfree(uint32_t iv) handlers[iv] = intr_routine_fallback; } -uint32_t -isrm_bindirq(uint32_t irq, isr_cb irq_handler) +int +isrm_bindirq(int irq, isr_cb irq_handler) { - uint32_t iv; + int iv; if (!(iv = isrm_ivexalloc(irq_handler))) { panickf("out of IV resource. (irq=%d)", irq); return 0; // never reach @@ -83,8 +83,8 @@ isrm_bindirq(uint32_t irq, isr_cb irq_handler) return iv; } -uint32_t -isrm_bindiv(uint32_t iv, isr_cb handler) +int +isrm_bindiv(int iv, isr_cb handler) { assert(iv < 256); if (iv >= IV_BASE) { @@ -94,7 +94,7 @@ isrm_bindiv(uint32_t iv, isr_cb handler) } isr_cb -isrm_get(uint32_t iv) +isrm_get(int iv) { assert(iv < 256); return handlers[iv]; diff --git a/lunaix-os/kernel/ds/waitq.c b/lunaix-os/kernel/ds/waitq.c index 4b5abfd..7045e36 100644 --- a/lunaix-os/kernel/ds/waitq.c +++ b/lunaix-os/kernel/ds/waitq.c @@ -5,6 +5,9 @@ void pwait(waitq_t* queue) { + // prevent race condition. + cpu_disable_interrupt(); + waitq_t* current_wq = &__current->waitqueue; assert(llist_empty(¤t_wq->waiters)); @@ -12,6 +15,8 @@ pwait(waitq_t* queue) block_current(); sched_yieldk(); + + cpu_enable_interrupt(); } void @@ -42,6 +47,7 @@ pwake_all(waitq_t* queue) { proc = container_of(pos, struct proc_info, waitqueue); + assert(proc->state == PS_BLOCKED); proc->state = PS_READY; llist_delete(&pos->waiters); } diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index d1643b4..53027c9 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -209,4 +209,9 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size) for (uintptr_t i = &__usrtext_start; i < &__usrtext_end; i += PG_SIZE) { vmm_set_mapping(PD_REFERENCED, i, V2P(i), PG_PREM_UR, VMAP_NULL); } + + // reserve higher half + for (size_t i = L1_INDEX(KERNEL_MM_BASE); i < 1023; i++) { + assert(vmm_set_mapping(PD_REFERENCED, i << 22, 0, 0, VMAP_NOMAP)); + } } diff --git a/lunaix-os/kernel/proc0.c b/lunaix-os/kernel/proc0.c index 54734f3..1e54e59 100644 --- a/lunaix-os/kernel/proc0.c +++ b/lunaix-os/kernel/proc0.c @@ -177,10 +177,11 @@ init_platform() // peripherals & chipset features ps2_kbd_init(); - pci_init(); block_init(); ahci_init(); + pci_init(); + // console console_start_flushing(); console_flush(); @@ -195,11 +196,6 @@ init_platform() vmm_del_mapping(PD_REFERENCED, (void*)i); pmm_free_page(KERNEL_PID, (void*)i); } - - // reserve higher half - for (size_t i = L1_INDEX(KERNEL_MM_BASE); i < 1023; i++) { - vmm_set_mapping(PD_REFERENCED, i << 22, 0, 0, VMAP_NOMAP); - } } void diff --git a/lunaix-os/kernel/process/sched.c b/lunaix-os/kernel/process/sched.c index 91932ca..f0c0a98 100644 --- a/lunaix-os/kernel/process/sched.c +++ b/lunaix-os/kernel/process/sched.c @@ -47,6 +47,8 @@ sched_init() sched_init_dummy(); } +#define DUMMY_STACK_SIZE 2048 + void sched_init_dummy() { @@ -54,28 +56,30 @@ sched_init_dummy() // It is a living nightmare! extern void my_dummy(); - static char dummy_stack[1024] __attribute__((aligned(16))); + static char dummy_stack[DUMMY_STACK_SIZE] __attribute__((aligned(16))); // memset to 0 dummy_proc = (struct proc_info){}; - dummy_proc.intr_ctx = - (isr_param){ .registers = { .ds = KDATA_SEG, - .es = KDATA_SEG, - .fs = KDATA_SEG, - .gs = KDATA_SEG, - .esp = (void*)dummy_stack + 1004 }, - .cs = KCODE_SEG, - .eip = (void*)my_dummy, - .ss = KDATA_SEG, - .eflags = cpu_reflags() | 0x0200 }; - - *(u32_t*)(&dummy_stack[1020]) = dummy_proc.intr_ctx.eflags; - *(u32_t*)(&dummy_stack[1016]) = KCODE_SEG; - *(u32_t*)(&dummy_stack[1012]) = dummy_proc.intr_ctx.eip; + dummy_proc.intr_ctx = (isr_param){ + .registers = { .ds = KDATA_SEG, + .es = KDATA_SEG, + .fs = KDATA_SEG, + .gs = KDATA_SEG, + .esp = (void*)dummy_stack + DUMMY_STACK_SIZE - 20 }, + .cs = KCODE_SEG, + .eip = (void*)my_dummy, + .ss = KDATA_SEG, + .eflags = cpu_reflags() | 0x0200 + }; + + *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 4]) = dummy_proc.intr_ctx.eflags; + *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 8]) = KCODE_SEG; + *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 12]) = dummy_proc.intr_ctx.eip; dummy_proc.page_table = cpu_rcr3(); dummy_proc.state = PS_READY; dummy_proc.parent = &dummy_proc; + dummy_proc.pid = KERNEL_PID; __current = &dummy_proc; } -- 2.27.0