From: acevest Date: Sun, 18 Jan 2026 08:51:28 +0000 (+0800) Subject: 支持SATA硬盘读取identify信息 X-Git-Url: http://repos.zhaoyanbai.com/Mou_128.png?a=commitdiff_plain;h=67f960ba672cef6a33faa0e81eedd5d1f0e2c385;p=kernel.git 支持SATA硬盘读取identify信息 --- diff --git a/drivers/ahci.c b/drivers/ahci.c new file mode 100644 index 0000000..4ea8f2c --- /dev/null +++ b/drivers/ahci.c @@ -0,0 +1,181 @@ +/* + * ------------------------------------------------------------------------ + * File Name: ahci.c + * Author: Zhao Yanbai + * 2026-01-16 21:32:08 Friday CST + * Description: none + * ------------------------------------------------------------------------ + */ + +#include +#include +#include +#include + +#include + +#include +#include + +void init_ahci_device(pci_device_t* pci, int index) { + assert(pci != NULL); + assert(index >= 0); + + printk("found ahci[%d] sata pci %03d:%02d.%d #%02d %04X:%04X\n", index, pci->bus, pci->dev, pci->devfn, + pci->intr_line, pci->vendor, pci->device); + + uint32_t bar5 = pci->bars[5]; + printk("ahci pci BAR5 value 0x%08X\n", bar5); + for (int i = 0; i < 6; i++) { + printk(" ahci pci BAR%u value 0x%08X\n", i, pci->bars[i]); + } + + pci_write_config_word(0xFFFFFFFF, PCI_BAR5); + uint32_t size = pci_read_config_word(PCI_BAR5); + assert(size > 0); +#if 1 + size += 1; +#else + size &= 0xFFFFFFF0; + size = (~size) + 1; +#endif + printk("ahci pci BAR5 size 0x%08X\n", size); + + uint32_t* mapped = ioremap(bar5, size); + if (mapped == NULL) { + panic("failed to map sata bar5\n"); + return; + } + printk("ahci pci BAR5 mapped to 0x%08X\n", mapped); + + struct { + uint32_t offset; + const char* name; + } regs[] = { + {0x00, "CAP"}, // + {0x04, "GHC"}, // + {0x08, "IS"}, // + {0x0C, "PI"}, // + {0x10, "VS"}, // + {0x14, "CCC_CTL"}, // + {0x18, "CCC_PORTS"}, // + {0x1C, "EM_LOC"}, // + {0x20, "EM_CTL"}, // + {0x24, "CAP2"}, // + {0x28, "BOHC"}, // + }; + + for (int i = 0; i < sizeof(regs) / sizeof(regs[0]); i++) { + uint32_t value = mapped[regs[i].offset / 4]; + printk(" ahci registers 0x%08X[%s]\n", value, regs[i].name); + } + + ahci_hba_t* hba = (ahci_hba_t*)mapped; + + hba->global_hba_control |= AHCI_ENABLE; + + uint32_t cap = hba->capability; + + int num_ports = (cap & 0x1F) + 1; + int num_cs = ((cap >> 8) & 0x1F) + 1; // command slots + int iss = (cap >> 20) & 0x0F; // interface speed support + int s64a = (cap >> 31) & 0x01; // supports 64bit addressing + printk("ahci ports %d cmd slots %d\n", num_ports, num_cs); + printk("support 64bit addressing %s\n", s64a ? "Y" : "N"); + + switch (iss) { + case 0b0001: + printk(" Gen1 (1.5 Gbps)\n"); + break; + case 0b0010: + printk(" Gen2 (3.0 Gbps)\n"); + break; + case 0b0100: + printk(" Gen3 (6.0 Gbps)\n"); + break; + default: + printk(" unknown interface speed support %02X\n", iss); + break; + } + + uint32_t ahci_pi = hba->ports_implemented; + printk("ahci port implemented %08X\n", ahci_pi); + + uint32_t ahci_version = hba->version; + char version[16]; + switch (ahci_version) { + case 0x00000905: + strcpy(version, "0.95"); + break; + case 0x00010000: + strcpy(version, "1.0"); + break; + case 0x00010100: + strcpy(version, "1.1"); + break; + case 0x00010200: + strcpy(version, "1.2"); + break; + case 0x00010300: + strcpy(version, "1.3"); + break; + case 0x00010301: + strcpy(version, "1.3.1"); + break; + default: + strcpy(version, "unknown"); + break; + } + printk("ahci version %s[%08x]\n", version, ahci_version); + + assert(sizeof(ahci_port_t) == 0x80); + int sata_index = 0; + for (int i = 0; i < num_ports; i++) { + if (ahci_pi & (1 << i)) { + ahci_port_t* port = hba->ports + i; + uint32_t sata_status = port->sata_status; + uint32_t sata_det = (sata_status >> 0) & 0x0F; // device detection + uint32_t sata_spd = (sata_status >> 4) & 0x0F; // current interface speed + uint32_t sata_ipm = (sata_status >> 8) & 0x0F; // interface power management + + if (sata_det != 3) { + continue; + } + + if (sata_ipm != 0x01) { + continue; + } + + switch (port->signature) { + case SATA_SIGNATURE_ATA: + printk("SATA device detected\n"); + extern void init_sata_device(ahci_hba_t * hba, ahci_port_t * port, int index); + init_sata_device(hba, port, sata_index); + sata_index++; + break; + case SATA_SIGNATURE_ATAPI: + printk("SATAPI device detected\n"); + break; + case SATA_SIGNATURE_SEMB: + printk("SEMB device detected\n"); + break; + case SATA_SIGNATURE_PM: + printk("PM device detected\n"); + break; + default: + printk("unknown ahci device detected\n"); + break; + } + } + } + + // TODO + // 开启ahci的global_hba_control的interrupt enable位 + hba->global_hba_control |= AHCI_INTERRUPT_ENABLE; +} + +void init_ahci() { + // progif + // 0x01 AHCI + pci_init_device(0x0106, 0x01, init_ahci_device); +} diff --git a/drivers/ahci.h b/drivers/ahci.h new file mode 100644 index 0000000..9852e57 --- /dev/null +++ b/drivers/ahci.h @@ -0,0 +1,152 @@ +/* + * ------------------------------------------------------------------------ + * File Name: ahci.h + * Author: Zhao Yanbai + * 2026-01-16 21:32:06 Friday CST + * Description: none + * ------------------------------------------------------------------------ + */ + +#pragma once + +#include + +const static int AHCI_PORT_COUNT = 32; +const static int AHCI_CMD_SLOT_COUNT = 32; + +const static int AHCI_DEVICE_NULL = 0; +const static int AHCI_DEVICE_SATA = 1; +const static int AHCI_DEVICE_SEMB = 2; +const static int AHCI_DEVICE_PM = 3; +const static int AHCI_DEVICE_SATAPI = 4; + +const static int AHCI_FIS_TYPE_REG_H2D = 0x27; +const static int AHCI_FIS_TYPE_REG_D2H = 0x34; + +typedef struct { + uint8_t fis_type; + uint8_t pmport : 4; // port multiplier + uint8_t _reserved0 : 3; + uint8_t c : 1; // 0: control; 1: command + + uint8_t command; + uint8_t feature; + + uint8_t lba0; + uint8_t lba1; + uint8_t lba2; + uint8_t device; + + uint8_t lba3; + uint8_t lba4; + uint8_t lba5; + uint8_t feature_high; + + uint8_t count_low; + uint8_t count_high; + uint8_t icc; + uint8_t control; + + uint8_t _reserved1[4]; +} ahci_fis_reg_h2d_t; + +typedef struct { + uint32_t data_base; // 第0位必为0 + + uint32_t _data_base_upper; + + uint32_t _reserved; + + uint32_t data_byte_count : 22; // 第0位必为1。另外该值表示实际为data_byte_count+1字节 + uint32_t _reserved1 : 9; + uint32_t ioc : 1; // interrupt on completion + +} ahci_prdt_entry_t; + +typedef struct { + // 0x00 - 0x40 + uint8_t cmd_fis[64]; + + // 0x40 - 0x50 + uint8_t _atapi_cmd[16]; // 12 or 16 bytes + + // 0x50 - 0x80 + uint8_t _reserved[48]; + + // 0x80 + ahci_prdt_entry_t prdt[0]; // update to 65536 entries +} ahci_cmd_table_t; + +// prd: physical region descriptor +typedef struct { + uint32_t cfl : 5; // length of the command fis: 命令FIS大小(双字为单位) + uint32_t a : 1; // 该命令需要发送到ATAPI设备 + uint32_t w : 1; // 该命令需要向设备写入数据 + uint32_t p : 1; // + uint32_t r : 1; + uint32_t b : 1; + uint32_t c : 1; // 命令执行完后,需要将 task_file_data的BSY位清零 + uint32_t R : 1; + uint32_t pmp : 4; + uint32_t prdtl : 16; // prdt entry count + + uint32_t prd_byte_count; // prd byte count + + uint32_t cmd_table_base; // 指向ahci_cmd_table_t + uint32_t _cmd_table_base_upper; + + uint32_t reserved[4]; +} ahci_cmd_header_t; + +typedef struct { + uint32_t cmd_list_base; + uint32_t _cmd_list_base_upper; + uint32_t fis_base; + uint32_t _fis_base_upper; + uint32_t interrupt_status; + uint32_t interrupt_enable; + uint32_t command_and_status; + uint32_t reserved; + uint32_t task_file_data; + uint32_t signature; + // DET[03:00]: Device Detection + // SPD[07:04]: Current Interface Speed + // IPM[11:08]: Interface Power Management + uint32_t sata_status; + uint32_t sata_control; + uint32_t sata_error; + uint32_t sata_active; + uint32_t cmd_issue; + uint32_t sata_notification; + uint32_t fis_base_switch_control; + uint32_t device_sleep; + uint32_t reserved2[10]; + uint32_t vendor_specific[4]; +} ahci_port_t; + +typedef struct { + // 0x00 - 0x2C + uint32_t capability; +#define AHCI_ENABLE 0x80000000 +#define AHCI_INTERRUPT_ENABLE 0x00000002 +#define AHCI_RESET 0x00000001 + uint32_t global_hba_control; + uint32_t interrupt_status; + uint32_t ports_implemented; + uint32_t version; + uint32_t ccc_ctrl; // command completion coalescing control + uint32_t ccc_ports; // command completion coalescing ports + uint32_t em_loc; // enclosure management location + uint32_t em_ctl; // enclosure management control + uint32_t capability_extended; // capability extended + uint32_t bios_handoff_control_status; + + // 0x2C - 0xA0 + uint8_t reserved[0xA0 - 0x2C]; + + // 0xA0 - 0x100 + uint8_t vendor_specific[0x100 - 0xA0]; + + // 0x100 + ahci_port_t ports[32]; +} ahci_hba_t; diff --git a/drivers/pci.c b/drivers/pci.c index c34bc08..eb5482b 100644 --- a/drivers/pci.c +++ b/drivers/pci.c @@ -132,7 +132,6 @@ pci_device_t* pci_find_device(unsigned int vendor, unsigned int device) { } pci_device_t* pci_find_device_by_classcode(unsigned int classcode) { - int i; list_head_t* p; pci_device_t* pci = 0; @@ -146,6 +145,24 @@ pci_device_t* pci_find_device_by_classcode(unsigned int classcode) { return 0; } +void pci_init_device(uint32_t classcode, uint32_t progif, void (*handler)(pci_device_t*, int)) { + list_head_t* p = NULL; + pci_device_t* pci = NULL; + + assert(handler != NULL); + + int index = 0; + + list_for_each(p, &pci_devs) { + pci = list_entry(p, pci_device_t, list); + assert(pci != NULL); + if (pci->classcode == classcode && pci->progif == progif) { + handler(pci, index); + index++; + } + } +} + const char* pci_intr_pin(int pin) { switch (pin) { case 0: diff --git a/drivers/sata.c b/drivers/sata.c index 369828b..a1755d2 100644 --- a/drivers/sata.c +++ b/drivers/sata.c @@ -7,200 +7,198 @@ * ------------------------------------------------------------------------ */ -#include -#include +#include +#include #include +#include +#include #include +#include -void init_sata() { - pci_device_t* pci = pci_find_device_by_classcode(0x0106); - if (pci == NULL) { - printk("can not find pci classcode: %08x", 0x0106); - printk("can not find sata controller"); - return; +void init_sata_device(ahci_hba_t* hba, ahci_port_t* port, int index) { + assert(hba != NULL); + assert(port != NULL); + assert(index >= 0 && index < MAX_SATA_DEVICES); + + sata_device_t* sata = sata_devices + index; + sata->hba = hba; + sata->port = port; + sata->index = index; + + printk("ahci port clb %08x fb %08x sata_status 0x%08X signature %08X\n", port->cmd_list_base, port->fis_base, + port->sata_status, port->signature); + + vaddr_t cmd_list_base = (vaddr_t)ioremap(PAGE_ALIGN(port->cmd_list_base), 0x1000); + vaddr_t fis_base = cmd_list_base; + + if (PAGE_ALIGN(port->cmd_list_base) != PAGE_ALIGN(port->fis_base)) { + fis_base = (vaddr_t)ioremap(PAGE_ALIGN(port->fis_base), 0x1000); } - // progif - // 0x01 AHCI + cmd_list_base += port->cmd_list_base - PAGE_ALIGN(port->cmd_list_base); + fis_base += port->fis_base - PAGE_ALIGN(port->fis_base); + + printk(" cmd_list_base %08x->%08x\n", port->cmd_list_base, cmd_list_base); + printk(" fis_base %08x->%08x\n", port->fis_base, fis_base); + + sata->cmd_list_base_vaddr = (ahci_cmd_header_t*)cmd_list_base; + sata->fis_base_vaddr = fis_base; + // - // 另外读取 BAR5 的 CAP 寄存器,如果 CAP 寄存器的 31 位为 1,则表示支持 AHCI 模式。 + // 1. 端口重置 + // 2. 分配空间,设置cmd_list_base, fis_base + // 3. 将sata_error清空 + // 4. 将需要使用的中断通过interrupt_enable开启 - if (pci->progif == 0x01) { - printk("AHCI mode supported\n"); - } else { - printk("AHCI mode not supported\n"); + // + assert(sizeof(ahci_cmd_header_t) == 32); + ahci_cmd_header_t* cmd_list = (ahci_cmd_header_t*)sata->cmd_list_base_vaddr; +#if 1 + for (int i = 0; i < 32; i++) { + ahci_cmd_header_t* hdr = &cmd_list[i]; + printk(" cmd_list[%02d] base %08x prdt %04x:%d\n", i, hdr->cmd_table_base, hdr->prdtl, hdr->prdtl); + hdr->cmd_table_base = 0; + hdr->prdtl = 0; } +#endif + + sata->cmd_table_paddr = (paddr_t)page2pa(alloc_one_page(0)); + sata->cmd_table_vaddr = (ahci_cmd_table_t*)ioremap(sata->cmd_table_paddr, PAGE_SIZE); + memset((void*)sata->cmd_table_vaddr, 0, PAGE_SIZE); + + sata->data_paddr = (paddr_t)page2pa(alloc_one_page(0)); + sata->data_vaddr = (vaddr_t)ioremap(sata->data_paddr, PAGE_SIZE); + memset((void*)sata->data_vaddr, 0, PAGE_SIZE); + + memset((void*)cmd_list, 0, sizeof(ahci_cmd_header_t)); + cmd_list[0].cfl = 0; + cmd_list[0].a = 0; + cmd_list[0].w = 0; + cmd_list[0].pmp = 0; + cmd_list[0].prdtl = 1; + cmd_list[0].prd_byte_count = 0; + cmd_list[0].cmd_table_base = sata->cmd_table_paddr; + sata->cmd_list0 = cmd_list; + + ahci_cmd_table_t* cmd_table = (ahci_cmd_table_t*)sata->cmd_table_vaddr; + memset(cmd_table, 0, sizeof(ahci_cmd_table_t)); + sata->cmd_table0 = cmd_table + 0; + sata->prdte0 = cmd_table[0].prdt + 0; + + sata->prdte0->data_base = sata->data_paddr; + sata->prdte0->data_byte_count = (512 - 1) | 1; + sata->prdte0->ioc = 1; - printk("found ahci sata pci progif %02x %03d:%02d.%d #%02d %04X:%04X\n", pci->progif, pci->bus, pci->dev, - pci->devfn, pci->intr_line, pci->vendor, pci->device); + // + ahci_fis_reg_h2d_t* fis = (ahci_fis_reg_h2d_t*)sata->cmd_table0->cmd_fis; + memset(fis, 0, sizeof(ahci_fis_reg_h2d_t)); + fis->fis_type = AHCI_FIS_TYPE_REG_H2D; + fis->c = 1; + fis->command = SATA_CMD_IDENTIFY; + fis->device = SATA_DEVICE_LBA; + + sata->cmd_list0->cfl = sizeof(ahci_fis_reg_h2d_t) / sizeof(uint32_t); + sata->cmd_list0->prdtl = 1; + sata->cmd_list0->w = 0; // read + sata->cmd_list0->a = 0; // ata device + sata->cmd_list0->prd_byte_count = 0; + + // 清除中断状态 + // 写1清0 + port->interrupt_status = port->interrupt_status; - uint32_t bar5 = pci->bars[5]; - printk("ahci pci BAR5 value 0x%08X\n", bar5); - for (int i = 0; i < 6; i++) { - printk(" ahci pci BAR%u value 0x%08X\n", i, pci->bars[i]); - // if (pci->bars[i] != 0) { - // assert((pci->bars[i] & 0x1) == 0x1); - // } - } + // + port->cmd_issue = 1 << 0; - pci_write_config_word(0xFFFFFFFF, PCI_BAR5); - uint32_t size = pci_read_config_word(PCI_BAR5); - printk("ahci pci BAR5 size 0x%08X\n", size); + uint32_t timeout = 1000000; + while (timeout--) { + if (port->interrupt_status & 1) { + break; + } + if (port->sata_error) { + printk("SATA ERROR: %08x\n", port->sata_error); + return; + } + asm("pause"); + } - assert(size > 0); - size += 1; + if (timeout == 0) { + printk("SATA TIMEOUT\n"); + return; + } - uint32_t* mapped = ioremap(bar5, size); - if (mapped == NULL) { - panic("failed to map sata bar5\n"); + if (sata->cmd_list0->prd_byte_count != 512) { + printk("SATA PRD BYTE COUNT: %08x\n", sata->cmd_list0->prd_byte_count); return; } - printk("ahci pci BAR5 mapped to 0x%08X\n", mapped); - - struct { - uint32_t offset; - const char* name; - uint32_t value; - } regs[] = { - {0x00, "CAP"}, // - {0x04, "GHC"}, // - {0x08, "IS"}, // - {0x0C, "PI"}, // - {0x10, "VS"}, // - {0x14, "CCC_CTL"}, // - {0x18, "CCC_PORTS"}, // - {0x1C, "EM_LOC"}, // - {0x20, "EM_CTL"}, // - {0x24, "CAP2"}, // - {0x28, "BOHC"}, // - }; - - for (int i = 0; i < sizeof(regs) / sizeof(regs[0]); i++) { - regs[i].value = mapped[regs[i].offset / 4]; - printk("ahci registers 0x%08X[%s]\n", regs[i].value, regs[i].name); + + printk("identify data %08x\n", sata->data_vaddr); + uint16_t* identify = (uint16_t*)sata->data_vaddr; + + // 第49个word的第8个bit位表示是否支持DMA + // 第83个word的第10个bit位表示是否支持LBA48,为1表示支持。 + // 第100~103个word的八个字节表示user的LBA最大值 + if ((identify[49] & (1 << 8)) != 0) { + sata->dma = 1; + } else { + panic("your sata disk drive do not support DMA"); } - uint32_t cap = mapped[0x00 / 4]; - int num_ports = (cap & 0x1F) + 1; - int num_cs = (cap >> 8) & 0x1F; // command slots - int iss = (cap >> 20) & 0x0F; // interface speed support - int s64a = (cap >> 31) & 0x01; - printk("ahci num_ports %d num_cs %d\n", num_ports, num_cs); - - switch (iss) { - case 0b0001: - printk(" Gen1 (1.5 Gbps)\n"); - break; - case 0b0010: - printk(" Gen2 (3.0 Gbps)\n"); - break; - case 0b0100: - printk(" Gen3 (6.0 Gbps)\n"); - break; - default: - printk(" unknown iss %02X\n", iss); - break; + uint64_t max_lba = 0; + + if ((identify[83] & (1 << 10)) != 0) { + sata->lba48 = 1; + max_lba = *(uint64_t*)(identify + 100); + } else { + panic("your sata disk drive do not support LBA48"); + // max_lba = (identify[61] << 16) | identify[60]; } - printk("support 64bit addressing %s\n", s64a ? "Y" : "N"); - - uint32_t ahci_pi = mapped[0x0C / 4]; - printk("ahci port implemented %08X\n", ahci_pi); - - uint32_t ahci_version = mapped[0x10 / 4]; - printk("ahci version 0x%08X\n", ahci_version); - - char version[16]; - switch (ahci_version) { - case 0x00000905: - strcpy(version, "0.95"); - break; - case 0x00010000: - strcpy(version, "1.0"); - break; - case 0x00010100: - strcpy(version, "1.1"); - break; - case 0x00010200: - strcpy(version, "1.2"); - break; - case 0x00010300: - strcpy(version, "1.3"); - break; - case 0x00010301: - strcpy(version, "1.3.1"); - break; - default: - strcpy(version, "unknown"); - break; + + sata->max_lba = max_lba; + + printk("%s %s size: %u MB ", sata->dma == 1 ? "DMA" : "", sata->lba48 == 1 ? "LBA48" : "LBA28", + (max_lba * 512) >> 20); + + uint16_t sata_major = identify[80]; + uint16_t sata_minor = identify[81]; + if (sata_major & (1 << 8)) { + printk("ATA8-ACS "); } - printk("ahci version %s\n", version); - - typedef struct { - uint32_t cmd_list_base; - uint32_t cmd_list_base_upper; - uint32_t fis_base; - uint32_t fis_base_upper; - uint32_t interrupt_status; - uint32_t interrupt_enable; - uint32_t command_and_status; - uint32_t reserved; - uint32_t task_file_data; - uint32_t signature; - uint32_t sata_status; - uint32_t sata_control; - uint32_t sata_error; - uint32_t sata_active; - uint32_t cmd_issue; - uint32_t sata_notification; - uint32_t fis_base_switch_control; - uint32_t device_sleep; - uint32_t reserved2[10]; - uint32_t vendor_specific[4]; - } ahci_port_t; - - assert(sizeof(ahci_port_t) == 0x80); - for (int i = 0; i < 32; i++) { - if (ahci_pi & (1 << i)) { - // printk("ahci port %d implemented\n", i); - ahci_port_t* port = (ahci_port_t*)(mapped + (0x100 + i * 0x80) / 4); - // printk("ahci port %d dt 0x%08X\n", i, port->command_and_status); - uint32_t sata_status = port->sata_status; - uint32_t sata_det = (sata_status >> 0) & 0x0F; - uint32_t sata_ipm = (sata_status >> 8) & 0x0F; - - if (sata_det != 3) { - continue; - } - - if (sata_ipm != 0x01) { - continue; - } - - printk("ahci port %d clb %08x fb %08x sata_status 0x%08X signature %08X\n", i, port->cmd_list_base, - port->fis_base, sata_status, port->signature); - -#define SATA_SIGNATURE_ATA 0x00000101 -#define SATA_SIGNATURE_ATAPI 0xEB140101 -#define SATA_SIGNATURE_SEMB 0xC33C0101 -#define SATA_SIGNATURE_PM 0x96690101 - - switch (port->signature) { - case SATA_SIGNATURE_ATA: - printk("SATA device detected\n"); - break; - case SATA_SIGNATURE_ATAPI: - printk("SATAPI device detected\n"); - break; - case SATA_SIGNATURE_SEMB: - printk("SEMB device detected\n"); - break; - case SATA_SIGNATURE_PM: - printk("PM device detected\n"); - break; - default: - printk("unknown device detected\n"); - break; - } - } + if (sata_major & (1 << 7)) { + printk("ATA/ATAPI-7 "); + } + if (sata_major & (1 << 6)) { + printk("ATA/ATAPI-6 "); + } + if (sata_major & (1 << 5)) { + printk("ATA/ATAPI-5 "); + } + if (sata_major & (1 << 4)) { + printk("ATA/ATAPI-4 "); + } + + printk("[Major %04X Minor %02X]\n", sata_major, sata_minor); + + char s[64]; + sata_read_identify_string(identify, 10, 19, s); + printk("SN: %s\n", s); + + sata_read_identify_string(identify, 23, 26, s); + printk("Firmware Revision: %s\n", s); + + sata_read_identify_string(identify, 27, 46, s); + printk("HD Model: %s\n", s); +} + +sata_device_t sata_devices[MAX_SATA_DEVICES] = {0}; + +void sata_read_identify_string(const uint16_t* identify, int bgn, int end, char* buf) { + const char* p = (const char*)(identify + bgn); + int i = 0; + for (; i <= (end - bgn); i++) { + buf[2 * i + 1] = p[0]; + buf[2 * i + 0] = p[1]; + p += 2; } + buf[i] = 0; } diff --git a/drivers/sata.h b/drivers/sata.h new file mode 100644 index 0000000..e233b16 --- /dev/null +++ b/drivers/sata.h @@ -0,0 +1,76 @@ +/* + * ------------------------------------------------------------------------ + * File Name: sata.h + * Author: Zhao Yanbai + * 2026-01-16 22:10:01 Friday CST + * Description: none + * ------------------------------------------------------------------------ + */ + +#pragma once + +#include +#include + +#define SATA_SIGNATURE_ATA 0x00000101 +#define SATA_SIGNATURE_ATAPI 0xEB140101 +#define SATA_SIGNATURE_SEMB 0xC33C0101 +#define SATA_SIGNATURE_PM 0x96690101 + +#define MAX_SATA_DEVICES 4 + +#define SATA_CMD_READ_PIO 0x20 +#define SATA_CMD_READ_PIO_EXT 0x24 +#define SATA_CMD_READ_DMA_EXT 0x25 +#define SATA_CMD_READ_DMA 0xC8 +#define SATA_CMD_IDENTIFY 0xEC + +// 参考ATA的DEVICE的定义 +// DEVICE寄存器 +// bit7: Obsolete Always set. +// bit6: L 如果为1,LBA Mode +// bit5: Obsolete Always set. +// bit4: DRIVE +// bit[0, 3] HS 如果L为0就是磁头号Head Number,如果L为1,则为LBA28的24-27位 +// 虽然理论上每个SATA端口复用器(PM)可以连接多个设备,但不计划支持,所以DRIVE位为0 +// 另外LBA在FIS中填写,所以bit0~3都可为0 +// 最后:在现代AHCI单设备场景中,这个字段通常被设为0,控制器会自动处理。大多数驱动设为0即可。 +// 所以这里定义成0x00 或 0xE0 都行 +#define SATA_DEVICE_LBA ((1 << 7) | (1 << 6) | (1 << 5)) + +typedef struct { + ahci_hba_t* hba; + ahci_port_t* port; + int index; + + int dma; // 是否支持dma + int lba48; // 是否支持lba48 + uint64_t max_lba; + + // 虽然有32个cmd header,但只用第0个 + ahci_cmd_header_t* cmd_list_base_vaddr; + vaddr_t fis_base_vaddr; + + // 分配一个cmd table页,但只用第0个cmd table + paddr_t cmd_table_paddr; + ahci_cmd_table_t* cmd_table_vaddr; + + // 分配一个prdt页,但只用第0个prdt entry + paddr_t prdte_paddr; + vaddr_t prdte_vaddr; + + // 分配一个数据页 + paddr_t data_paddr; + vaddr_t data_vaddr; + + // 第0个cmd header + ahci_cmd_header_t* cmd_list0; + // 第0个cmd table + ahci_cmd_table_t* cmd_table0; + // 第0个prdte + ahci_prdt_entry_t* prdte0; +} sata_device_t; + +extern sata_device_t sata_devices[MAX_SATA_DEVICES]; + +void sata_read_identify_string(const uint16_t* identify, int bgn, int end, char* buf); diff --git a/include/pci.h b/include/pci.h index 773cac8..fb4cf4c 100644 --- a/include/pci.h +++ b/include/pci.h @@ -268,6 +268,8 @@ typedef union pci_device pci_device_t* pci_find_device(unsigned int vendor, unsigned int device); pci_device_t* pci_find_device_by_classcode(unsigned int classcode); +void pci_init_device(uint32_t classcode, uint32_t progif, void (*handler)(pci_device_t* pci, int index)); + static inline u32 pci_cmd(pci_device_t* pci, unsigned int reg) { return PCI_CMD(pci->bus, pci->dev, pci->devfn, reg); } diff --git a/kernel/setup.c b/kernel/setup.c index 544c590..68218d7 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -191,8 +191,8 @@ void setup_kernel() { void ide_init(); ide_init(); #endif - void init_sata(); - init_sata(); + void init_ahci(); + init_ahci(); void dump_fixmap(); dump_fixmap(); diff --git a/qemu.sh b/qemu.sh index a6aedc4..b4bbf40 100755 --- a/qemu.sh +++ b/qemu.sh @@ -19,18 +19,18 @@ set -m qemu-system-i386 \ -boot d \ - -m 3100\ + -m 128\ -smp 2 \ -cpu qemu32,+x2apic \ -machine q35 \ -serial tcp::6666,server,nowait \ - -drive file=hd.img,format=raw,index=0,media=disk \ - -drive file=kernel.iso,index=1,media=cdrom \ -drive file=sata.img,format=raw,if=none,id=sata-disk \ + -drive file=sata2.img,format=raw,if=none,id=sata-disk2 \ -drive file=kernel.iso,format=raw,if=none,id=atapi-cdrom \ -device ahci,id=ahci0 \ -device ide-hd,drive=sata-disk,bus=ahci0.0 \ -device ide-cd,drive=atapi-cdrom,bus=ahci0.1 \ + -device ide-hd,drive=sata-disk2,bus=ahci0.5 \ -name kernel \ -vga std \ -display cocoa \