当前版本实现了DMA传输模式, 并且在bochs, VirtualBox及VMware下都测试通过, 目前只有ATA硬盘读写操作使用的是DMA模式, ATAPI光盘使用的还是PIO模式, 读者有兴趣的话, 可以自行修改驱动来实现ATAPI的DMA传输模式。DMA传输模式是直接在内存与磁盘之间传输数据, 所以理论上速度比PIO模式要快, 这点在 VirtualBox与VMware下得到了很好的验证。
zenglOX v2.4.0 DMA(Direct Memory Access) 当前版本实现了DMA传输模式, 并且在bochs, VirtualBox及VMware下都测试通过, 目前只有ATA硬盘读写操作使用的是DMA模式, ATAPI光盘使用的还是PIO模式, 读者有兴趣的话, 可以自行修改驱动来实现ATAPI的DMA传输模式。 DMA传输模式是直接在内存与磁盘之间传输数据, 所以理论上速度比PIO模式要快, 这点在 VirtualBox与VMware下得到了很好的验证。 但是在bochs下, 如果你不修改它的源代码的话, 默认情况下, DMA表现的速度比PIO模式还要 慢, 主要是它的代码里, 和DMA读写操作相关的定时器的值, 设置的太大了。 因此作者对其定时器值做了些修改, 并放到sourceforge对应版本的网盘里, 文件为pci_ide.cc , 假设你的bochs源码的路径为/mnt/zenglOX/bochs-2.6 , 那么就将该pci_ide.cc文件放置到/mnt/zenglOX/bochs-2.6/iodev/目录下, 覆盖掉 该目录下原来的pci_ide.cc文件。 (我这里是对之前一直在用的bochs-2.6的版本进行的修改, 请确保你和我是一样的版本, 在之前zenglOX v0.0.1的网盘里, 我提供过bochs-2.6 的源代码, 并在zenglOX v0.0.1及zenglOX v2.0.0的文章里介绍过bochs-2.6的编译过程 , 目前bochs的编译过程请以zenglOX v2.0.0版本为主, 因为该版本的编译过程中 加入了E1000网卡与PCI总线的支持, 如果你之前已经按照zenglOX v2.0.0版本的要求, 编译过bochs了, 那么在替换了pci_ide.cc文件后, 就只需执行make和make install命令 即可(请用root权限), 这样它就只会去编译修改过的文件, 其他没修改过的文件就可以跳过编译) pci_ide.cc文件里, 主要修改了第397行的代码: //bx_pc_system.activate_timer(BX_PIDE_THIS s.bmdma[channel].timer_index, 1000, 0); bx_pc_system.activate_timer(BX_PIDE_THIS s.bmdma[channel].timer_index, 1, 0); 也就是将activate_timer函数的第二个参数由1000改为1 , 这样每次触发DMA读写操作时, 就不用等那么久了(原来的定时器间隔大概是1000 usecond的时间) 读者可以在修改pci_ide.cc之前, 先运行一下zenglOX, 看下默认情况下原始的DMA 读写速度, 然后修改pci_ide.cc并编译安装bochs后, 再看下DMA的读写速度情况, 你就会发现他们在速度上的差异了。 在VirtualBox与VMware下则不存在这种情况, 他们的DMA速度明显比PIO模式要快。 zenglOX当前版本中, 和DMA相关的驱动代码主要集中在新增的zlox_ide.c文件里。 需要参考sourceforge网盘里的DMA_program.pdf手册, 才能理解代码的含义。 在前一个版本的说明文档里, 作者曾说过DMA驱动很难写, 原因就是作者只有PDF 手册可以作为参考, 没有实际的源代码可供研究, 作者根据手册里的说明写出来的 驱动程式在一开始时, 遇到了很多问题, 最后都是通过调试bochs源代码, 分析其中IDE 控制器, ATA驱动器相关的代码, 在充分理解其工作方式后, 才写出一个比较通用的DMA驱动程式的。 因此, 如果没有bochs的源代码的话, 这个驱动程式估计还写不出来(PDF手册里的 说明信息并不是完全正确的, 有些说明信息甚至有非常致命的错误, 只有通过调试 bochs源代码才能分析出来, 因此PDF手册也只能作为一种大概的参考) 当前版本只是增加了DMA驱动, 并修复了一些小BUG, 除此之外, 没作别的大的改动, zenglOX源代码的编译运行过程和之前v2.3.0版本的方式一样, 也没有增加新的命令行程式。 时间: 2014年11月15日 作者: zenglong 官网: www.zengl.com |
[email protected]:~$ cd Downloads/ [email protected]:~/Downloads$ sudo cp pci_ide.cc /mnt/zenglOX/bochs-2.6/iodev/ [sudo] password for zengl: [email protected]:~/Downloads$ vim /mnt/zenglOX/bochs-2.6/iodev/pci_ide.cc [email protected]:~/Downloads$ cd /mnt/zenglOX/bochs-build/ [email protected]:/mnt/zenglOX/bochs-build$ sudo make [email protected]:/mnt/zenglOX/bochs-build$ sudo make install |
[email protected]:~/Downloads$ unzip -d zenglOX_v2.4.0 zenglOX_v2.4.0.zip [email protected]:~/Downloads$ cd zenglOX_v2.4.0/ [email protected]:~/Downloads/zenglOX_v2.4.0$ make [email protected]:~/Downloads/zenglOX_v2.4.0$ make iso [email protected]:~/Downloads/zenglOX_v2.4.0$ chmod +x startBochs [email protected]:~/Downloads/zenglOX_v2.4.0$ ifconfig -a eth0 Link encap:以太网 硬件地址 08:00:27:07:a0:9a inet 地址:10.0.2.15 广播:10.0.2.255 掩码:255.255.255.0 ..................................................... [email protected]:~/Downloads/zenglOX_v2.4.0$ vim bochsrc.txt [email protected]:~/Downloads/zenglOX_v2.4.0$ sudo ./startBochs |
[email protected]:~/Downloads$ cd zenglOX_v2.4.0/ [email protected]:~/Downloads/zenglOX_v2.4.0$ gdb -q zenglOX.bin Reading symbols from /home/zengl/Downloads/zenglOX_v2.4.0/zenglOX.bin...done. (gdb) target remote localhost:1234 Remote debugging using localhost:1234 0x0000fff0 in ?? () (gdb) c Continuing. Remote connection closed (gdb) q [email protected]:~/Downloads/zenglOX_v2.4.0$ |
#makefile for zenglOX .................................................... DEPS = zlox_common.h zlox_monitor.h zlox_descriptor_tables.h zlox_isr.h zlox_time.h zlox_kheap.h \ zlox_paging.h zlox_ordered_array.h zlox_initrd.h zlox_fs.h zlox_multiboot.h zlox_task.h \ zlox_keyboard.h zlox_elf.h zlox_ata.h zlox_iso.h zlox_zenglfs.h zlox_vga.h zlox_pci.h \ zlox_e1000.h zlox_network.h zlox_ps2.h zlox_uheap.h zlox_ide.h OBJS = zlox_boot.o zlox_kernel.o zlox_common.o zlox_monitor.o zlox_descriptor_tables.o \ zlox_gdt.o zlox_interrupt.o zlox_isr.o zlox_time.o zlox_kheap.o zlox_paging.o \ zlox_ordered_array.o zlox_initrd.o zlox_fs.o zlox_task.o zlox_process.o zlox_syscall.o \ zlox_keyboard.o zlox_elf.o zlox_shutdown.o zlox_ata.o zlox_iso.o zlox_zenglfs.o zlox_vga.o \ zlox_pci.o zlox_e1000.o zlox_network.o zlox_ps2.o zlox_uheap.o zlox_ide.o INITRD_IMG = build_initrd_img/initrd.img .................................................... |
// 通过PCI配置空间, 检测IDE控制器是否支持Bus Master, 如果支持,则对 // Bus Master IDE的status状态寄存器, Descriptor Table Pointer Register即物理内存区域描述符表指针寄存器 // 进行配置, 从而为DMA传输作准备 ZLOX_SINT32 zlox_ide_probe() { ..................................................... ZLOX_UINT32 prdt_phy = 0; ZLOX_UINT32 prdt_u32 = zlox_kmalloc_ap(8, &prdt_phy); ZLOX_UINT32 pr_mem_buf_phy = 0; ide_pr_mem_buf = (ZLOX_UINT8 *)zlox_kmalloc_ap(2048, &pr_mem_buf_phy); ZLOX_UINT32 * prdt_ptr = (ZLOX_UINT32 *)prdt_u32; prdt_ptr[0] = pr_mem_buf_phy; //prdt_ptr[1] = (2048 | 0x80000000); //如果将物理内存区域的大小设置为2048的话, 则bochs下运行时会出现问题 prdt_ptr[1] = (1024 | 0x80000000); zlox_outl(ide_reg_base + 0x4, prdt_phy); prdt_phy = 0; prdt_u32 = zlox_kmalloc_ap(8, &prdt_phy); pr_mem_buf_phy = 0; ide_pr_mem_buf2 = (ZLOX_UINT8 *)zlox_kmalloc_ap(2048, &pr_mem_buf_phy); prdt_ptr = (ZLOX_UINT32 *)prdt_u32; prdt_ptr[0] = pr_mem_buf_phy; //prdt_ptr[1] = (2048 | 0x80000000); prdt_ptr[1] = (1024 | 0x80000000); zlox_outl(ide_reg_base + 0xC, prdt_phy); ..................................................... } |
Offset from Base Address |
Register |
Register Access |
---|---|---|
00h |
Bus Master IDE Command register Primary 第一个通道(主通道)对应的Bus Master命令寄存器 |
R/W |
01h | Device Specific | |
02h |
Bus Master IDE Status register Primary 主通道对应的Bus Master状态寄存器 |
RWC |
03h | Device Specific | |
04h-07h |
Bus Master IDE PRD Table Address Primary 主通道对应的Bus Master物理内存区域描述符表 指针寄存器 |
R/W |
08h |
Bus Master IDE Command register Secondary 第二个通道(从通道)对应的Bus Master命令寄存器 |
R/W |
09h | Device Specific | |
0Ah |
Bus Master IDE Status register Secondary 从通道对应的Bus Master状态寄存器 |
RWC |
0Bh | Device Specific | |
0Ch-0Fh |
Bus Master IDE PRD Table Address Secondary 从通道对应的Bus Master物理内存区域描述符表 指针寄存器 |
R/W |
ZLOX_SINT32 zlox_ide_probe() { for(ZLOX_UINT32 i = 0; i < pci_devconf_lst.count ;i++) { if(pci_devconf_lst.ptr[i].cfg_hdr.class_code == 0x01 && pci_devconf_lst.ptr[i].cfg_hdr.sub_class == 0x01 && ((pci_devconf_lst.ptr[i].cfg_hdr.prog_if & 0x80) != 0)) { //if(pci_devconf_lst.ptr[i].cfg_hdr.vend_id != 0x8086 || // pci_devconf_lst.ptr[i].cfg_hdr.dev_id != 0x7111) // return -1; ide_reg_base = pci_devconf_lst.ptr[i].cfg_hdr.bars[4]; if((ide_reg_base & 0x1) == 0) { return -1; } else ide_reg_base = ide_reg_base & (~0x03); ................................................ ................................................ } } |
Bit | Description |
---|---|
7:4 |
Reserved. Must return 0 on reads. 保留位,读取时必须返回0 |
3 |
Read or Write Control: This bit sets the direction of the bus master transfer: when set to zero, PCI bus master reads are performed. When set to one, PCI bus master writes are performed. This bit must NOT be changed when the bus master function is active. 读写控制位,这里的英文说明有问题,应该是当执行READ DMA即DMA读操作时,该二进制位需要 设置为1,当执行WRITE DMA即DMA写操作时,该二进制位需要被清0,该二进制位必须在向ATA 驱动器发送具体的读写命令之前进行设置。 |
2:1 |
Reserved. Must return 0 on reads. 保留位,读取时必须返回0 |
0 |
Start/Stop Bus Master: DMA传输的启动和停止位,当向该二进制位写入1时,就会立即触发DMA的 传输操作,如果在传输的过程中写入0的话,就会中止DMA的传输,并且所有状态信息都会被丢失,因此, 一般是在DMA传输后(可以通过状态寄存器里的中断位或Active位来判断传输是否结束),才向该位写入0 。 |
Bit | Description |
---|---|
7 |
Simplex only: This read-only bit indicates whether or not both bus master channels (primary and secondary) can be operated at the same time. If the bit is a '0', then the channels operate independently and can be used at the same time. If the bit is a '1', then only one channel may be used at a time. 该二进制位(只读)用于判断主从两个通道是否可以同时执行DMA总线操作,如果为0,则表示两个 通道的操作是独立的,可以同时执行总线操作,当为1时,则同一时间内,只能有一个通道可以被用于 执行总线操作。 |
6 |
Drive 1 DMA Capable: This read/write bit is set by device dependent code (BIOS or device driver) to indicate that drive 1 for this channel is capable of DMA transfers, and that the controller has been initialized for optimum performance. 该二进制位用于判断Drive 1即通道上的slave从设备是否具备DMA的传输能力,这通常是由设备相关的代码 (例如BIOS或设备驱动程式)来进行设置,在bochs下,一开始它的BIOS不会对其进行设置,因此,需要我们的驱动程式 来将其设置为1。 |
5 |
Drive 0 DMA Capable: This read/write bit is set by device dependent code (BIOS or device driver) to indicate that drive 0 for this channel is capable of DMA transfers, and that the controller has been initialized for optimum performance. 用于判断Drive 0即通道上的master主设备是否具备DMA的传输能力,驱动程式中也会对其进行设置。 |
4:3 |
Reserved. Must return 0 on reads. 保留位,读取时必须返回0 |
2 |
Interrupt: This bit is set by the rising edge of the IDE interrupt line. This bit is cleared when a '1' is written to it by software. Software can use this bit to determine if an IDE device has asserted its interrupt line. When this bit is read as a one, all data transfered from the drive is visible in system memory. 中断位:通过该二进制位,可以检测通道上的IDE设备(例如ATA驱动器)是否发送了中断信号。 驱动程式里可以通过向该位写入1来将其清零。当通道中出现中断信号时,即该位被设置为1时, 就表示DMA操作执行完毕,可以配合下面的Error错误位,来判断DMA传输过程中,是否发生了错误。 |
1 |
Error: This bit is set when the controller encounters an error in transferring data to/from memory. The exact error condition is bus specific and can be determined in a bus specific manner. This bit is cleared when a '1' is written to it by software. 错误位:当DMA数据传输过程中,发生错误时,该二进制位就会被设置。具体的出错原因,可以 通过PCI配置空间里的Status状态寄存器的值,以及ATA驱动器的状态寄存器的值,来进行判断。 |
0 |
Bus Master IDE Active: This bit is set when the Start bit is written to the Command register. This bit is cleared when the last transfer for a region is performed, where EOT for that region is set in the region descriptor. It is also cleared when the Start bit is cleared in the Command register. When this bit is read as a zero, all data transfered from the drive during the previous bus master command is visible in system memory, unless the bus master command was aborted. 通过该Active二进制位,可以判断DMA总线操作是否开始,以及总线操作是否执行完毕。 当该位被设置为1时,则表示DMA操作已经开始。当该位被清零时,则表示DMA传输结束。 可以配合上面的Error错误位,来判断传输过程中,是否发生了错误。 |
Bit | Description |
---|---|
31:2 |
Base address of Descriptor table. Corresponds to A[31:2] 描述符表的物理内存地址。 |
1:0 |
reserved 保留位 |
1) Software prepares a PRD Table in system memory. Each PRD is 8 bytes long and consists of an address pointer to the starting address and the transfer count of the memory buffer to be transferred. In any given PRD Table, two consecutive PRDs are offset by 8-bytes and are aligned on a 4-byte boundary. 1):驱动程式需要在系统内存里,分配一个PRD表即物理内存区域描述符表, 表中的每一项都为8字节尺寸的描述符,还要为描述符分配对应的物理内存区域。 并且,描述符的起始物理地址,需要按照4字节来对齐。 2) Software provides the starting address of the PRD Table by loading the PRD Table Pointer Register . The direction of the data transfer is specified by setting the Read/Write Control bit. Clear the Interrupt bit and Error bit in the Status register. 2):驱动程式需要将PRD表的起始物理内存地址,加载到PRD表指针寄存器中。 每次DMA读写操作之前,需要设置Bus Master命令寄存器里的读写控制位,以控制DMA数据传输的方向, 在开启传输之前,还需要将Bus Master状态寄存器里的中断位及错误位清零。 3) Software issues the appropriate DMA transfer command to the disk device. 3):驱动程式向ATA磁盘设备发送相应的DMA读写命令(例如READ DMA命令或WRITE DMA命令等) 4) Engage the bus master function by writing a '1' to the Start bit in the Bus Master IDE Command Register for the appropriate channel. 4):在向ATA设备发送DMA读写命令后,需要将当前通道对应的Bus Master命令寄存器里的Start/Stop Bus Master位设置为1,从而正式开启DMA的传输操作。 5) The controller transfers data to/from memory responding to DMA requests from the IDE device. 5):IDE控制器就会通过DMA总线,将数据从IDE设备传输到物理内存区域中,或者从物理内存区域 传输到IDE设备中。 6) At the end of the transfer the IDE device signals an interrupt. 6):DMA传输结束后,IDE设备就会发送中断信号。 7) In response to the interrupt, software resets the Start/Stop bit in the command register. It then reads the controller status and then the drive status to determine if the transfer completed successfully. 7):驱动程式可以通过Bus Master Status状态寄存器里的中断位来判断是否产生了中断信号, 当产生了中断信号时,则说明数据传输完毕了。此外,VirtualBox下,当ATA与ATAPI设备位于 同一个通道中时,可能会出现收不到中断信号的情况,这种情况下,可以通过状态寄存器里的 Bus Master IDE Active位来判断数据是否传输完毕了,最后,再配合状态寄存器的Error错误 位,就可以检测数据传输过程中是否发生了错误。 |
....................................................... extern ZLOX_PCI_DEVCONF_LST pci_devconf_lst; ZLOX_UINT32 ide_reg_base = 0; ZLOX_UINT8 * ide_pr_mem_buf = ZLOX_NULL; ZLOX_UINT8 * ide_pr_mem_buf2 = ZLOX_NULL; ZLOX_UINT32 ide_pci_index; ZLOX_BOOL ide_can_dma = ZLOX_FALSE; // 通过PCI配置空间, 检测IDE控制器是否支持Bus Master, 如果支持,则对 // Bus Master IDE的status状态寄存器, Descriptor Table Pointer Register即物理内存区域描述符表指针寄存器 // 进行配置, 从而为DMA传输作准备 ZLOX_SINT32 zlox_ide_probe() { for(ZLOX_UINT32 i = 0; i < pci_devconf_lst.count ;i++) { if(pci_devconf_lst.ptr[i].cfg_hdr.class_code == 0x01 && pci_devconf_lst.ptr[i].cfg_hdr.sub_class == 0x01 && ((pci_devconf_lst.ptr[i].cfg_hdr.prog_if & 0x80) != 0)) { //if(pci_devconf_lst.ptr[i].cfg_hdr.vend_id != 0x8086 || // pci_devconf_lst.ptr[i].cfg_hdr.dev_id != 0x7111) // return -1; ide_reg_base = pci_devconf_lst.ptr[i].cfg_hdr.bars[4]; if((ide_reg_base & 0x1) == 0) { return -1; } else ide_reg_base = ide_reg_base & (~0x03); ZLOX_UINT32 ide_reg_status = zlox_inb(ide_reg_base + 0x2); zlox_outb(ide_reg_base + 0x2, ide_reg_status | 0x60); ide_reg_status = zlox_inb(ide_reg_base + 0xa); zlox_outb(ide_reg_base + 0xa, ide_reg_status | 0x60); ZLOX_UINT16 cr = zlox_pci_reg_inw(pci_devconf_lst.ptr[i].cfg_addr, ZLOX_PCI_REG_COMMAND); if (!(cr & ZLOX_PCI_COMMAND_MAST_EN)) zlox_pci_reg_outw(pci_devconf_lst.ptr[i].cfg_addr, ZLOX_PCI_REG_COMMAND, cr | ZLOX_PCI_COMMAND_MAST_EN); ZLOX_UINT32 prdt_phy = 0; ZLOX_UINT32 prdt_u32 = zlox_kmalloc_ap(8, &prdt_phy); ZLOX_UINT32 pr_mem_buf_phy = 0; ide_pr_mem_buf = (ZLOX_UINT8 *)zlox_kmalloc_ap(2048, &pr_mem_buf_phy); ZLOX_UINT32 * prdt_ptr = (ZLOX_UINT32 *)prdt_u32; prdt_ptr[0] = pr_mem_buf_phy; //prdt_ptr[1] = (2048 | 0x80000000); //如果将物理内存区域的大小设置为2048的话, 则bochs下运行时会出现问题 prdt_ptr[1] = (1024 | 0x80000000); zlox_outl(ide_reg_base + 0x4, prdt_phy); prdt_phy = 0; prdt_u32 = zlox_kmalloc_ap(8, &prdt_phy); pr_mem_buf_phy = 0; ide_pr_mem_buf2 = (ZLOX_UINT8 *)zlox_kmalloc_ap(2048, &pr_mem_buf_phy); prdt_ptr = (ZLOX_UINT32 *)prdt_u32; prdt_ptr[0] = pr_mem_buf_phy; //prdt_ptr[1] = (2048 | 0x80000000); prdt_ptr[1] = (1024 | 0x80000000); zlox_outl(ide_reg_base + 0xC, prdt_phy); ide_pci_index = i; ide_can_dma = ZLOX_TRUE; return 0; } } return -1; } // 在发送ATA磁盘读写命令之前, 需要先将Bus Master IDE Command命令寄存器的读写位进行设置, 让IDE控制器知道 // 当前是读操作还是写操作, 另外还需要将Bus Master IDE Status状态寄存器里的中断位与错误位清零 ZLOX_SINT32 zlox_ide_before_send_command(ZLOX_UINT8 direction, ZLOX_UINT16 bus) { if(ide_can_dma == ZLOX_FALSE) return -1; ZLOX_UINT32 cmd_port; if(bus == ZLOX_ATA_BUS_PRIMARY) cmd_port = ide_reg_base + 0x0; else cmd_port = ide_reg_base + 0x8; if(direction == 0) zlox_outb(cmd_port, 0x08); else zlox_outb(cmd_port, 0); ZLOX_UINT32 ide_reg_status; ZLOX_UINT16 status_port; if(bus == ZLOX_ATA_BUS_PRIMARY) status_port = ide_reg_base + 0x2; else status_port = ide_reg_base + 0xa; ide_reg_status = zlox_inb(status_port); ide_reg_status |= 0x6; // 只有向中断位和Error错误位写入1, 才能将其清零 zlox_outb(status_port, ide_reg_status); return 0; } // 通过将Bus Master IDE Command命令寄存器的位0即Start/Stop Bus Master位设置为1, 就可以触发DMA总线读写操作 ZLOX_SINT32 zlox_ide_start_dma(ZLOX_UINT16 bus) { if(ide_can_dma == ZLOX_FALSE) return -1; ZLOX_UINT16 cmd_port; if(bus == ZLOX_ATA_BUS_PRIMARY) cmd_port = ide_reg_base + 0x0; else cmd_port = ide_reg_base + 0x08; ZLOX_UINT32 ide_reg_command = zlox_inb(cmd_port); zlox_outb(cmd_port, ide_reg_command | 0x1); return 0; } // 在DMA总线读写操作完毕后, 需要通过Bus Master IDE status状态寄存器来检测中断位 或 Bus Master IDE Active位, // 当中断位为1时(即ATA驱动器发送了中断信号), 则说明读写操作完成, 当然也有可能是发生了错误而中断了传输, 要判断是否发生错误 // 可以通过状态寄存器的Error错误位来进行检测 // 此外, 由于VirtualBox下, 当ATA与ATAPI驱动位于同一个channel通道时, 因为它们共用一个中断信号, 因此会导致对ATAPI读操作后, ATA驱动无法 // 检测到中断信号的情况, 这种情况下, 我们就需要通过Bus Master IDE status状态寄存器的Bus Master IDE Active位来进行检测了, // 当Active位为0时, 则说明数据传输完毕, 或者发生错误而中断了传输, 同样也可以配合Error错误位来进行判断 ZLOX_SINT32 zlox_ide_after_send_command(ZLOX_UINT16 bus) { if(ide_can_dma == ZLOX_FALSE) return -1; ZLOX_UINT8 ide_reg_status = 0; for(;;) { if(bus == ZLOX_ATA_BUS_PRIMARY) ide_reg_status = zlox_inb(ide_reg_base + 0x2); else ide_reg_status = zlox_inb(ide_reg_base + 0xa); if(((ide_reg_status & 0x4) != 0) || ((ide_reg_status & 0x1) == 0)) { if((ide_reg_status & 0x2) != 0) { if(bus == ZLOX_ATA_BUS_PRIMARY) zlox_outb(ide_reg_base + 0x0, 0); else zlox_outb(ide_reg_base + 0x8, 0); ZLOX_UINT16 status = pci_devconf_lst.ptr[ide_pci_index].cfg_hdr.status; zlox_monitor_write("ide error , pci status: "); zlox_monitor_write_hex((ZLOX_UINT32)status); zlox_monitor_write("\n"); zlox_monitor_write("ide error , pci dev_id: "); zlox_monitor_write_hex((ZLOX_UINT32)pci_devconf_lst.ptr[ide_pci_index].cfg_hdr.dev_id); zlox_monitor_write("\n"); return -1; } if(bus == ZLOX_ATA_BUS_PRIMARY) zlox_outb(ide_reg_base + 0x0, 0); else zlox_outb(ide_reg_base + 0x8, 0); return 1; } else asm volatile ("pause"); } return 0; } // 从物理内存区域中获取DMA传输的数据 ZLOX_SINT32 zlox_ide_get_buffer_data(ZLOX_UINT8 * buffer, ZLOX_UINT32 len, ZLOX_UINT16 bus) { if(ide_can_dma == ZLOX_FALSE) return -1; if(bus == ZLOX_ATA_BUS_PRIMARY) zlox_memcpy(buffer, ide_pr_mem_buf, len); else zlox_memcpy(buffer, ide_pr_mem_buf2, len); return 0; } // 要写入ATA磁盘的数据, 需要先写入到物理内存区域中, 稍后再通过DMA总线传输到磁盘里 ZLOX_SINT32 zlox_ide_set_buffer_data(ZLOX_UINT8 * buffer, ZLOX_UINT32 len, ZLOX_UINT16 bus) { if(ide_can_dma == ZLOX_FALSE) return -1; if(bus == ZLOX_ATA_BUS_PRIMARY) zlox_memcpy(ide_pr_mem_buf, buffer, len); else zlox_memcpy(ide_pr_mem_buf2, buffer, len); return 0; } |
// Read/Write From ATA Drive, direction == 0 is read, direction == 1 is write ZLOX_SINT32 zlox_ide_ata_access(ZLOX_UINT8 direction, ZLOX_UINT8 ide_index, ZLOX_UINT32 lba, ZLOX_UINT8 numsects, ZLOX_UINT8 * buffer) { .................................................... // (V) Select the command and send it; if (lba_mode == 0 && direction == 0) cmd = ide_can_dma ? 0xC8 : 0x20; // READ DMA OR READ SECTOR(S) if (lba_mode == 1 && direction == 0) cmd = ide_can_dma ? 0xC8 : 0x20; // READ DMA OR READ SECTOR(S) if (lba_mode == 2 && direction == 0) cmd = ide_can_dma ? 0x25 : 0x24; // READ DMA EXT or READ SECTOR(S) EXT command (support from ATA-ATAPI-6) if (lba_mode == 0 && direction == 1) cmd = ide_can_dma ? 0xCA : 0x30; // WRITE DMA or WRITE SECTOR(S) command if (lba_mode == 1 && direction == 1) cmd = ide_can_dma ? 0xCA : 0x30; // WRITE DMA or WRITE SECTOR(S) command if (lba_mode == 2 && direction == 1) cmd = ide_can_dma ? 0x35 : 0x34; // WRITE DMA EXT or WRITE SECTOR(S) EXT command (support from ATA-ATAPI-6) if(ide_can_dma) { zlox_ide_before_send_command(direction, bus); if(direction == 1) zlox_ide_set_buffer_data(buffer, numsects * ZLOX_ATA_SECTOR_SIZE, bus); } zlox_outb (ZLOX_ATA_COMMAND (bus), cmd); if(ide_can_dma) zlox_ide_start_dma(bus); if(ide_can_dma) { // DMA Read. if (direction == 0) { if(zlox_ide_after_send_command(bus) == -1) { status = zlox_inb (ZLOX_ATA_COMMAND (bus)); if (status & 0x1) { ZLOX_UINT8 error = zlox_inb (ZLOX_ATA_FEATURES (bus)); zlox_monitor_write("ata error , error reg: "); zlox_monitor_write_hex((ZLOX_UINT32)error); zlox_monitor_write("\n"); return -1; } return -1; } zlox_ide_get_buffer_data(buffer, numsects * ZLOX_ATA_SECTOR_SIZE, bus); } else // DMA Write. { if(zlox_ide_after_send_command(bus) == -1) { status = zlox_inb (ZLOX_ATA_COMMAND (bus)); if (status & 0x1) { ZLOX_UINT8 error = zlox_inb (ZLOX_ATA_FEATURES (bus)); zlox_monitor_write("ata error , error reg: "); zlox_monitor_write_hex((ZLOX_UINT32)error); zlox_monitor_write("\n"); return -1; } return -1; } } } else { // PIO Read. if (direction == 0) { .................................................... } else // PIO Write. { .................................................... } } zlox_outb(ZLOX_ATA_DCR(bus), control_orig); return 0; } |
zenglOX v3.0.2 PNG(Portable Network Graphics) and BUG Fix
zenglOX v0.0.11 ELF format(ELF可执行文件格式)与execve系统调用
zenglOX v0.0.9 User Mode(用户模式)
zenglOX v1.4.0与v1.4.1 通过ATA驱动读写硬盘里的数据, BUG修复, VirtualBox与VMware的调试功能
zenglOX v2.2.0 ee(easy editor)文本编辑器 C标准库函数 uheap(单独的用户堆空间) atapi驱动BUG zenglfs文件系统BUG 分页BUG 堆算法BUG等修复