#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)",
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)
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.");
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;
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);
*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;
ahci_register_device(hbadev);
}
+
+ return ahci_drv;
}
void
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)
{
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
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;
#include <hal/acpi/acpi.h>
#include <hal/apic.h>
#include <hal/pci.h>
+#include <klibc/string.h>
#include <lunaix/fs/twifs.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/spike.h>
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);
.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
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) {
#define AHCI_HBA_CLASS 0x10601
+struct ahci_driver
+{
+ struct llist_header ahci_drvs;
+ struct ahci_hba hba;
+ int id;
+};
+
/**
* @brief 初始化AHCI与HBA
*
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);
#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)
#define HBA_DEV_FATAPI (1 << 1)
struct hba_port;
+struct ahci_hba;
struct hba_device
{
uint32_t block_per_sec;
uint32_t capabilities;
struct hba_port* port;
+ struct ahci_hba* hba;
struct
{
struct hba_cmd_context cmdctx;
void* fis;
struct hba_device* device;
+ struct ahci_hba* hba;
};
struct ahci_hba
#include <hal/io.h>
#include <lunaix/ds/llist.h>
+#include <lunaix/types.h>
#define PCI_CONFIG_ADDR 0xcf8
#define PCI_CONFIG_DATA 0xcfc
#define BAR_TYPE_MMIO 0x1
#define BAR_TYPE_CACHABLE 0x2
+#define PCI_DRV_NAME_LEN 32
+
+struct pci_driver;
struct pci_base_addr
{
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"
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 */
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 */
}
}
-static inline uint32_t
+static inline int
__ivalloc_within(size_t a, size_t b, isr_cb handler)
{
a = (a - IV_BASE) / 8;
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) {
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
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) {
}
isr_cb
-isrm_get(uint32_t iv)
+isrm_get(int iv)
{
assert(iv < 256);
return handlers[iv];
void
pwait(waitq_t* queue)
{
+ // prevent race condition.
+ cpu_disable_interrupt();
+
waitq_t* current_wq = &__current->waitqueue;
assert(llist_empty(¤t_wq->waiters));
block_current();
sched_yieldk();
+
+ cpu_enable_interrupt();
}
void
{
proc = container_of(pos, struct proc_info, waitqueue);
+ assert(proc->state == PS_BLOCKED);
proc->state = PS_READY;
llist_delete(&pos->waiters);
}
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));
+ }
}
// peripherals & chipset features
ps2_kbd_init();
- pci_init();
block_init();
ahci_init();
+ pci_init();
+
// console
console_start_flushing();
console_flush();
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
sched_init_dummy();
}
+#define DUMMY_STACK_SIZE 2048
+
void
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;
}