* Description: none
* ------------------------------------------------------------------------
*/
-
#include <ata.h>
+#include <ide.h>
#include <io.h>
+#include <string.h>
#include <system.h>
#include <types.h>
+extern ide_pci_controller_t ide_pci_controller;
+void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *);
+
+void *mbr_buf;
+
// 本程序参考文档《AT Attachment with Packet Interface - 6》
-// https://wiki.osdev.org/ATA_PIO_Mode
-// To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the slave,
-// to the "drive select" IO port. On the Primary bus, this would be port 0x1F6. Then set the Sectorcount, LBAlo,
-// LBAmid, and LBAhi IO ports to 0 (port 0x1F2 to 0x1F5). Then send the IDENTIFY command (0xEC) to the Command IO
-// port (0x1F7).
-// Then read the Status port (0x1F7) again. If the value read is 0, the drive does not exist. For any
-// other value: poll the Status port (0x1F7) until bit 7 (BSY, value = 0x80) clears. Because of some ATAPI drives
-// that do not follow spec, at this point you need to check the LBAmid and LBAhi ports (0x1F4 and 0x1F5) to see if
-// they are non-zero. If so, the drive is not ATA, and you should stop polling. Otherwise, continue polling one of
-// the Status ports until bit 3 (DRQ, value = 8) sets, or until bit 0 (ERR, value = 1) sets. At that point, if ERR
-// is clear, the data is ready to read from the Data port (0x1F0). Read 256 16-bit values, and store them.
-//
-// ATAPI的情况暂时不用考虑,因为不是硬盘相关的
-// https://wiki.osdev.org/ATAPI
-// ATAPI refers to devices that use the Packet Interface of the ATA6 (or higher) standard command set. It is
-// basically a way to issue SCSI commands to a CD-ROM, CD-RW, DVD, or tape drive, attached to the ATA bus.
-//
-// 总结来说,仅考虑ATA硬盘的情况
+// 仅考虑ATA硬盘的情况
// 一个IDE接口能接Master、Slave两个DRIVE。
// 一个PC机上通常有两个IDE接口(IDE0, IDE1或ATA0, ATA1),通常称通道0、1
// 对于同一个IDE通道的两个DRIVE,共享同一组寄存器,它们之间的区分是通过Device寄存器的第4个bit位来实现的。0为Master,1为Slave
//
// 使用IDENTIFY命令步骤:
-// 1. 选择DRIVE,发送0xA0选择master,发送0xB0选择slave。(发送 0xE0 | (drive << 4)到Device寄存器)
-// 2. 发送0到该DRIVE所在通道的寄存器NSECTOR, LBAL, LBAM, LBAH
-// 3. 发送IDENTIFY(0xEC)命令到该通道的命令寄存器
+// 1. 选择DRIVE构造命令,发送到Device寄存器(发送到master: 0x00, 发送到slave: 0x40)
+// 2. 发送IDENTIFY(0xEC)命令到该通道的命令寄存器
// 检查status寄存器:
// 1. 若为0,就认为没有IDE
// 2. 等到status的BSY位清除
// 3. 等到status的DRQ位或ERR位设置
u16 identify[256];
void ata_read_identify(int dev) { // 这里所用的dev是逻辑编号 ATA0、ATA1下的Master、Salve的dev分别为0,1,2,3
+#if 1
outb(0x00 | ((dev & 0x01) << 4), REG_DEVICE(dev)); // 根据文档P113,这里不用指定bit5, bit7,直接指示DRIVE就行
outb(ATA_CMD_IDENTIFY, REG_CMD(dev));
while (1) {
u64 lba = *(u64 *)(identify + 100);
printk("hard disk size: %u MB\n", (lba * 512) >> 20);
}
+#endif
+ printk("bus iobase %x cmd %x status %x prdt %x \n", ide_pci_controller.bus_iobase, ide_pci_controller.bus_cmd,
+ ide_pci_controller.bus_status, ide_pci_controller.bus_prdt);
+
+ mbr_buf = kmalloc(512, 0);
+ memset(mbr_buf, 0xAA, 512);
+ ata_dma_read_ext(0, 0, 1, mbr_buf);
+}
+
+// ATA_CMD_READ_DMA_EXT
+void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *addr) {
+ // 停止DMA BusMasterIDEStatusRegister
+ outb(0x00, ide_pci_controller.bus_iobase + 0);
+
+ // 配置描述符表
+ unsigned long *p = (unsigned long *)addr;
+ unsigned long paddr = va2pa(addr);
+ ide_pci_controller.prdt[0].phys_addr = paddr;
+ ide_pci_controller.prdt[0].byte_count = 512;
+ ide_pci_controller.prdt[0].reserved = 0;
+ ide_pci_controller.prdt[0].eot = 1;
+ printk("paddr: %x prdt: %x %x prdte %x %x\n", paddr, ide_pci_controller.prdt, va2pa(ide_pci_controller.prdt),
+ ide_pci_controller.prdt[0].phys_addr, *(((unsigned int *)ide_pci_controller.prdt) + 1));
+ outl(va2pa(ide_pci_controller.prdt), ide_pci_controller.bus_iobase + 4);
+
+ // 清除中断位和错误位
+ // 这里清除的方式是是设置1后清除
+ uint8_t t = inb(ide_pci_controller.bus_iobase + 2);
+ printk("ide pci status %x\n", t);
+ outb(t | 0x06, ide_pci_controller.bus_iobase + 2);
+
+ // 选择DRIVE
+ outb(ATA_LBA48_DEVSEL(dev), REG_DEVICE(dev));
+
+ // 不再设置nIEN,DMA需要中断
+ outb(0x00, REG_CTL(dev));
+
+ // 先写扇区数的高字节
+ outb((count >> 8) & 0xFF, REG_NSECTOR(dev));
+
+ // 接着写LBA48,高三个字节
+ outb((pos >> 24) & 0xFF, REG_LBAL(dev));
+ outb((pos >> 32) & 0xFF, REG_LBAM(dev));
+ outb((pos >> 40) & 0xFF, REG_LBAH(dev));
+
+ // 再写扇区数的低字节
+ outb((count >> 0) & 0xFF, REG_NSECTOR(dev));
+
+ // 接着写LBA48,低三个字节
+ outb((pos >> 0) & 0xFF, REG_LBAL(dev));
+ outb((pos >> 8) & 0xFF, REG_LBAM(dev));
+ outb((pos >> 16) & 0xFF, REG_LBAH(dev));
+
+ outb(ATA_CMD_READ_DMA_EXT, REG_CMD(dev));
+
+ // 设置开始停止位为1,开始DMA
+ // 并且指定为读取硬盘操作
+ // DMA对硬盘而言是写出,所以设置bit 3为1
+ outb(0x09, ide_pci_controller.bus_iobase + 0);
+}
+
+uint8_t ata_pci_bus_status() {
+ uint8_t st = 0;
+ st = inb(ide_pci_controller.bus_iobase + 2);
+ return st;
}
unsigned int ATA_CHL0_CMD_BASE = 0x1F0;
#define ATA_LBAH 5
// DEVICE寄存器
-// bit7: 1
+// bit7: Obsolete
// bit6: L 如果为1,LBA Mode
-// bit5: 1
+// bit5: Obsolete
// bit4: DRIVE
// bit[0, 3] HS 如果L为0就是磁头号Head Number,如果L为1,则为LBA的24-27位
+#define ATA_LBA48_DEVSEL(dev) (0x40 | ((dev & 0x01) << 4))
#define ATA_DEVICE 6
#define ATA_CMD 7
*/
// #include <assert.h>
-// #include <ide.h>
+#include <ide.h>
// #include <io.h>
// #include <irq.h>
-// #include <pci.h>
+
// #include <printk.h>
// #include <sched.h>
// #include <semaphore.h>
// #include <types.h>
// #include <wait.h>
-// typedef struct _ide_drv {
-// pci_device_t *pci;
-// unsigned long pio_cnt;
-// unsigned long dma_cnt;
-// unsigned long irq_cnt;
-
-// unsigned int iobase;
-
-// unsigned int bus_cmd;
-// unsigned int bus_status;
-// unsigned int bus_prdt;
-
-// unsigned int read_mode;
-
-// u64_t ext_lba_base;
-// part_t part[MAX_SUPPORT_PARTITION_CNT];
-// } ide_drive_t;
-
// typedef struct prd {
// unsigned int addr;
// unsigned int cnt : 16;
// unsigned int sys_clock();
-// void ide_pci_init(pci_device_t *pci) {
-// unsigned int v;
+ide_pci_controller_t ide_pci_controller;
-// v = pci_read_config_word(pci_cmd(pci, PCI_COMMAND));
-// printk(" ide pci command %04x\n", v);
+extern unsigned int ATA_CHL0_CMD_BASE;
+extern unsigned int ATA_CHL1_CMD_BASE;
-// v = pci_read_config_byte(pci_cmd(pci, PCI_PROGIF));
-// printk(" ide pci program interface %02x\n", v);
+extern unsigned int ATA_CHL0_CTL_BASE;
+extern unsigned int ATA_CHL1_CTL_BASE;
-// unsigned int iobase = pci_read_config_long(pci_cmd(pci, PCI_BAR4));
-// printk(" ide pci Base IO Address Register %08x\n", iobase);
-// iobase &= 0xFFFC; // 最低为0是内存地址为1是端口地址
-// drv.iobase = iobase;
-// drv.bus_cmd = iobase + PCI_IDE_CMD;
-// drv.bus_status = iobase + PCI_IDE_STATUS;
-// drv.bus_prdt = iobase + PCI_IDE_PRDT;
+void ide_pci_init(pci_device_t *pci) {
+ unsigned int v;
-// int i;
-// printk(" BARS: ");
-// for (i = 0; i < BARS_CNT; ++i) {
-// printk("%08x ", pci->bars[i]);
-// pci->bars[i] &= (~1UL);
-// }
-// printk("\n");
+ v = pci_read_config_word(pci_cmd(pci, PCI_COMMAND));
+ printk(" ide pci command %04x\n", v);
-// HD_CHL0_CMD_BASE = pci->bars[0] ? pci->bars[0] : HD_CHL0_CMD_BASE;
-// HD_CHL0_CTL_BASE = pci->bars[1] ? pci->bars[1] : HD_CHL0_CTL_BASE;
+ v = pci_read_config_byte(pci_cmd(pci, PCI_PROGIF));
+ printk(" ide pci program interface %02x\n", v);
-// HD_CHL1_CMD_BASE = pci->bars[2] ? pci->bars[2] : HD_CHL1_CMD_BASE;
-// HD_CHL1_CTL_BASE = pci->bars[3] ? pci->bars[3] : HD_CHL1_CTL_BASE;
+ unsigned int iobase = pci_read_config_long(pci_cmd(pci, PCI_BAR4));
+ printk(" ide pci Base IO Address Register %08x\n", iobase);
+ iobase &= 0xFFFC; // 最低为0是内存地址为1是端口地址
+ ide_pci_controller.bus_iobase = iobase;
+ ide_pci_controller.bus_cmd = iobase + PCI_IDE_CMD;
+ ide_pci_controller.bus_status = iobase + PCI_IDE_STATUS;
+ ide_pci_controller.bus_prdt = iobase + PCI_IDE_PRDT;
-// printk("channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x\n", HD_CHL0_CMD_BASE, HD_CHL0_CTL_BASE,
-// HD_CHL1_CMD_BASE, HD_CHL1_CTL_BASE);
-// // printl(18, "channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x", HD_CHL0_CMD_BASE, HD_CHL0_CTL_BASE,
-// // HD_CHL1_CMD_BASE, HD_CHL1_CTL_BASE);
-// }
+ ide_pci_controller.prdt = (prdte_t *)alloc_one_page(0);
+
+ int i;
+ printk(" BARS: ");
+ for (i = 0; i < BARS_CNT; ++i) {
+ printk("%08x ", pci->bars[i]);
+ pci->bars[i] &= (~1UL);
+ }
+ printk("\n");
+
+ ATA_CHL0_CMD_BASE = pci->bars[0] ? pci->bars[0] : ATA_CHL0_CMD_BASE;
+ ATA_CHL0_CTL_BASE = pci->bars[1] ? pci->bars[1] : ATA_CHL0_CTL_BASE;
+
+ ATA_CHL1_CMD_BASE = pci->bars[2] ? pci->bars[2] : ATA_CHL1_CMD_BASE;
+ ATA_CHL1_CTL_BASE = pci->bars[3] ? pci->bars[3] : ATA_CHL1_CTL_BASE;
+
+ printk("channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x\n", ATA_CHL0_CMD_BASE, ATA_CHL0_CTL_BASE,
+ ATA_CHL1_CMD_BASE, ATA_CHL1_CTL_BASE);
+ // printl(18, "channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x", HD_CHL0_CMD_BASE, HD_CHL0_CTL_BASE,
+ // HD_CHL1_CMD_BASE, HD_CHL1_CTL_BASE);
+}
// void ide_status() {
// u8_t idest = inb(REG_STATUS(0));
// kfree(buf);
// }
-// void init_pci_controller(unsigned int classcode) {
-// pci_device_t *pci = pci_find_device_by_classcode(classcode);
-// if (pci != 0 && pci->intr_line < 16) {
-// printk("found pci vendor %04x device %04x class %04x intr %d\n", pci->vendor, pci->device, pci->classcode,
-// pci->intr_line);
-// // printl(17, "found pci vendor %04x device %04x class %04x intr %d", pci->vendor, pci->device,
-// pci->classcode,
-// // pci->intr_line);
-// ide_pci_init(pci);
-// drv.pci = pci;
-// }
-// }
+void init_pci_controller(unsigned int classcode) {
+ pci_device_t *pci = pci_find_device_by_classcode(classcode);
+ if (pci != 0 && pci->intr_line < 16) {
+ printk("found pci vendor %04x device %04x class %04x intr %d\n", pci->vendor, pci->device, pci->classcode,
+ pci->intr_line);
+ // printl(17, "found pci vendor %04x device %04x class %04x intr %d", pci->vendor, pci->device,
+ // pci->classcode,
+ // pci->intr_line);
+ ide_pci_init(pci);
+ ide_pci_controller.pci = pci;
+ }
+}
void ide_default_intr() {}
// void ide_default_intr() {
// // printd("%s\n", __func__);
// memset((void *)&drv, 0, sizeof(drv));
// init_pci_controller(0x0106);
- // init_pci_controller(0x0101);
+ init_pci_controller(0x0101);
// ide_detect();
// return;
#pragma once
-// #include <system.h>
+#include <pci.h>
+#include <system.h>
// extern unsigned int HD_CHL0_CMD_BASE;
// extern unsigned int HD_CHL1_CMD_BASE;
// #define ATA_IDENT_COMMANDSETS 164
// #define ATA_IDENT_MAX_LBA_EXT 200
-// #define PCI_IDE_CMD 0
-// #define PCI_IDE_CMD_STOP 0x00
-// #define PCI_IDE_CMD_READ 0x00
-// #define PCI_IDE_CMD_START 0x01
-// #define PCI_IDE_CMD_WRITE 0x08
-// #define PCI_IDE_STATUS 2
-// #define PCI_IDE_STATUS_ACT 0x01
-// #define PCI_IDE_STATUS_ERR 0x02
-// #define PCI_IDE_STATUS_INTR 0x04
-// #define PCI_IDE_STATUS_DRV0 0x20
-// #define PCI_IDE_STATUS_DRV1 0x40
-// #define PCI_IDE_STATUS_SIMPLEX 0x80
-// #define PCI_IDE_PRDT 4
+#define PCI_IDE_CMD 0
+#define PCI_IDE_CMD_STOP 0x00
+#define PCI_IDE_CMD_READ 0x00
+#define PCI_IDE_CMD_START 0x01
+#define PCI_IDE_CMD_WRITE 0x08
+#define PCI_IDE_STATUS 2
+#define PCI_IDE_STATUS_ACT 0x01
+#define PCI_IDE_STATUS_ERR 0x02
+#define PCI_IDE_STATUS_INTR 0x04
+#define PCI_IDE_STATUS_DRV0 0x20
+#define PCI_IDE_STATUS_DRV1 0x40
+#define PCI_IDE_STATUS_SIMPLEX 0x80
+#define PCI_IDE_PRDT 4
// #define PARTITION_CNT 4
// #define PARTITION_TABLE_OFFSET 0x1BE
// void ide_do_read(u64_t lba, u32_t scnt, char *buf);
// part_t *ide_get_part(dev_t dev);
+
+// Physical Region Descriptor
+typedef struct prdte {
+ uint32_t phys_addr;
+ uint32_t byte_count : 16;
+ uint32_t reserved : 15;
+ uint32_t eot : 1;
+} prdte_t;
+typedef struct _ide_pci_controller {
+ pci_device_t *pci;
+
+ unsigned int bus_iobase;
+ unsigned int bus_cmd;
+ unsigned int bus_status;
+ unsigned int bus_prdt;
+
+ prdte_t *prdt;
+} ide_pci_controller_t;
\ No newline at end of file
_bt; \
})
-#define outb(value, port) ({ __asm__("outb %%al,%%dx" : : "a"(value), "d"(port)); })
+#define outb(value, port) ({ __asm__("outb %%al,%%dx" : : "a"((uint8_t)(value)), "d"(port)); })
-#define outw(value, port) ({ __asm__("outw %%ax,%%dx" : : "a"(value), "d"(port)); })
-#define outl(value, port) ({ __asm__("outl %%eax,%%dx" : : "a"(value), "d"(port)); })
+#define outw(value, port) ({ __asm__("outw %%ax,%%dx" : : "a"((uint16_t)(value)), "d"(port)); })
+#define outl(value, port) ({ __asm__("outl %%eax,%%dx" : : "a"((uint32_t)(value)), "d"(port)); })
#define outb_p(value, port) ({ __asm__("outb %%al,%%dx;nop;nop;nop;nop" : : "a"(value), "d"(port)); })
prev->next = next;
}
-static inline void list_del(list_head_t *entry) {
- _list_del(entry->prev, entry->next);
- entry->prev = NULL;
- entry->next = NULL;
-}
+static inline void list_del(list_head_t *entry) { _list_del(entry->prev, entry->next); }
static inline void list_del_init(list_head_t *entry) {
_list_del(entry->prev, entry->next);
#pragma once
#include <list.h>
+#include <types.h>
#define PCI_ADDR 0xCF8 // CONFIG_ADDRESS
#define PCI_DATA 0xCFC // CONFIG_DATA
typedef unsigned char u8_t;
typedef unsigned short u16_t;
typedef unsigned long u32_t;
-typedef unsigned long u32_t;
typedef unsigned long long u64_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+
typedef unsigned long pid_t;
typedef unsigned long mode_t;
system_delay();
- setup_tasks();
+ // setup_tasks();
setup_irqs();
void ide_init();
ide_init();
- asm("cli;hlt;");
+ while (1) {
+ asm("sti;hlt;");
+ }
extern tty_t monitor_tty;
// tty_switch(&monitor_tty);
// asm("sti");
}
void ide_irq();
+extern void *mbr_buf;
+uint8_t ata_pci_bus_status();
+
void default_ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) {
- // printk("default irq handler %d \n", irq);
- ide_irq();
+ printk("default irq handler %d \n", irq);
+
+ printk("ide pci status after interrupt: %x", ata_pci_bus_status());
+
+ uint16_t *p = (uint16_t *)mbr_buf;
+ for (int i = 0; i < 256; i++) {
+ if (i % 12 == 0) {
+ printk("\n%03d ", i);
+ }
+ printk("%04x ", p[i]);
+ }
}
void default_irq_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) { printk("default irq handler %d \n", irq); }
}
}
+ // 先关闭所有中断
for (int i = 0; i < 16; i++) {
close_irq(i);
}
+ // 清除8259A的级连中断引脚的中断屏蔽位
+ // 以让从片的中断在放开后能发送到CPU
+ open_irq(2);
+
+ // 打开支持的中断
open_irq(0x00);
open_irq(0x01);
open_irq(0x0A);