tag 标签: ahci

相关博文
  • 热度 19
    2015-4-23 17:21
    1407 次阅读|
    0 个评论
    (3)分析得到的数据   DOS下运行:  ahci1 F7906000 0 得到如下结果:   tablebuff  SEG=1870   OFF=0000    FLAT ADDR=00018700 databuff  SEG=18A4   OFF=0000    FLAT ADDR=00018A40 COMMAND HEADER in hex is: 05 00 01 00 00 00 00 00 00 87 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   COMMAND TABLE in hex is: 27 80 EC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 8A 01 00 00 00 00 00 00 00 00 00 E7 03 00 80     HBA addr=F7906000H  PORT addr=F7906100H   HBA MEM in hex is: 45 FF 30 CF 00 00 00 80 00 00 00 00 05 00 00 00 00 03 01 00 00 00 00 00 00 00 00 00 02 00 60 01 00 00 01 07 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 1E 31 00 1F 00 00 00 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   分析如下: 45 FF 30 CF   1100 1111   0011 0000       1111 1111      0100 0101                                                  支持6个口                                  支持32个SLOT             支持6Gbps   00 00 00 80 10000000 00000000 00000000 000000  0  0 AHCI已激活                                    总中断使能=0                                       未复位   00 00 00 00 各口没有中断产生   05 00 00 00 00000000 00000000 000000 00000101                               第0、第2口有接设备   00 03 01 00      00 00 00 00        00 00 00 00      02 00 60 01 版本号1.3.0     不支持CCC功能      CCC口             00 00 01 07      04 00 00 00   00 00 00 00    00 00 00 00 不支持PM功能    扩展功能      控制权空闲   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   以下是VENDOR自己的东东: 78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 1E 31 00 1F 00 00 00 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     PORT MEM in hex is: 00 DC 09 00 00 00 00 00 00 E0 09 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 50 00 00 00 01 01 00 00 23 01 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   分析如下: 00 DC 09 00   00 00 00 00    00 E0 09 00   00 00 00 00 CML地址                     接收FIS地址   00 00 00 00     00 00 00 00    06 00 00 00      00 00 00 00 IS无中断事件   中断使能=0    不支持POD,SUD                               不是APAPI设备                               command list未运行                               不接收FIS!!                               不处理COMMAND LIST!!   50 00 00 00              01 01 00 00      23 01 00 00               00 03 00 00 TFD,无ERR,无DRQ,无BSY                 当前速度是2               不限速,不切换到其它电源状态 ERR=5                                    PxSSTS.DET = 3设备已连接     00 00 00 00      00 00 00 00           00 00 00 00         00 00 00 00 SERR无错误      用于“原生队列命令”   CI未占用SLOT       用于Port Multiplier                  SACT未占用SLOT          00 00 00 00             00 00 00 00 00 00 00 00 00 00 00 00 用于Port Multiplier    保留   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   另外,接SSD硬盘的PORT2的MEM如下: 00 DC 09 00 00 00 00 00 00 E0 09 00 00 00 00 00 CML地址                     接收FIS地址   ---与PORT0是一样的地址!!!   00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 ---与PORT0数据一样 50 00 00 00 01 01 00 00 23 01 00 00 00 03 00 00 ---与PORT0数据一样 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ---与PORT0数据一样 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 HAVE COPY COMMAND HEADER TO SLOT0    HAVE SET PxCMD.FRE   PxCMD is 00004016         --0100 0000 0001 0110 FRE设为1后,FR也变成1了   HAVE SET PxCMD.ST    PxCMD is 0000C017         --1100 0000 0001 0111 ST设为1后,CR也变成1了   data buff in hex is:  读出硬盘的512字节数据如下: 5A 04 FF 3F 37 C8 10 00 00 00 00 00 3F 00 00 00 00 00 00 00 20 20 20 20 20 20 32 4A 38 31 30 30 33 35 41 45 55 54 44 4E 03 00 00 40 04 00 45 4A 4F 44 36 41 41 30 69 48 61 74 68 63 20 69 54 48 35 53 37 34 36 35 41 34 45 39 38 33 20 34 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80 00 40 00 2F 00 40 00 02 00 02 07 00 FF 3F 10 00 3F 00 10 FC FB 00 10 01 FF FF FF 0F 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00 00 00 00 00 00 00 1F 00 06 17 00 00 5E 00 40 00 FC 01 28 00 6B 74 69 7D 63 61 69 74 49 BC 63 61 7F 20 51 00 52 00 80 40 FE FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B0 82 85 4A 00 00 00 00 00 00 00 00 03 60 6C 82 00 50 A6 CC E1 3E EB 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 40 18 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00   29 00 0B 00 00 00 00 00 82 21 F1 1C 00 FA 00 00 00 40 00 04 08 01 00 00 00 00 04 0A 04 0A 03 0A 05 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 33 44 36 44 00 00 04 29 00 00 AD 5D 18 25 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3D 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 15 00 00 00 00 00 00 00 00 1F 10 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 E0 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A5 4C   分析如下:每个WORD都是高字节在后 (参见ATA-7标准,EC命令) (WORD0)5A 04 FF 3F       柱面总个数=16383 37 C8 10 00       磁头总个数=16 00 00 00 00 每磁道所含的字节数,每扇区所含的字节数 3F 00       每磁道所含的扇区总个数=63                          即: 16383×16×63 =16514064扇区,8455200768字节,即8.4G的硬盘                  与“INT 13H扩展”报告的是一样的 00 00 00 00 00 00      (WORD10)20 20 20 20 20 20 32 4A 38 31 30 30 33 35 41 45 55 54 44 4E     序列号20字节ASCII     内存中排列是2J810035AEUTDN,真实是J2180053EATUND                 即每个WORD是高字节在后,但多个WORD的排列顺序是从前到后的   03 00 00 40     硬盘缓冲区容量 04 00   ECC校验码的长度   45 4A 4F 44 36 41 41 30    软体版本号8字节ASCII   内存中排列是EJOD6AA0 ,真实是JEDOA60A           69 48 61 74 68 63 20 69 54 48 35 53 37 34 36 35 41 34 45 39 38 33 20 34 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20       硬盘型号40字节ASCII   (WORD47)10 80 00 40 00 2F capabilities 00 40 capabilities 00 02 00 02 obsolete 07 00 FF 3F 10 00 3F 00 10 FC FB 00 10 01 (WORD60)FF FF FF 0F   Total number of user addressable sectors  (扇区数,用于LBA28位寻址时用的)                       The maximum value that shall be placed in this field is 0FFFFFFFh   00 00 (WORD63)07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 (WORD71)00 00 00 00 00 00 00 00 1F 00 = 0001 1111 06 17 00 00 5E 00 40 00 (WORD80)FC 01   Major version number  0000 0001 1111 1100 28 00    Minor version number 6B 74   (WORD83 )69 7D     bit 10 word 83 为1时,indicates support for 48-bit addressing   63 61 69 74 49 BC 63 61 (WORD88)7F 20 51 00 52 00 80 40 FE FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00   (WORD100) B0 82 85 4A 00 00 00 00 Maximum user LBA for 48-bit Address feature set( 扇区总数 ,用于LBA48位寻址用的)       //值比最大LBA再多1,LBA是从0开始的,故这里的值就是扇区总数,与AIDA检测一致       //= 1250263728 *512= 640GB   00 00 00 00 (WORD106)03 60   Physical sector size / Logical Sector Size          =01(有效)  1(1个物理扇区有多个逻辑扇区)0(words117-118无效,逻辑扇区是512字节) 0000 0000 0011                        8 logical sector per physical sector,即1个物理扇区是8个逻辑扇区(4KB)                        即产生4KB对齐的问题   6C 82 00 50 A6 CC E1 3E EB 17   World wide name 00 00 00 00 00 00 00 00 00 00   (WORD117)00 00 00 00   Logical Sector Size  这里无效   18 40 18 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00   29 00 0B 00 00 00 00 00 82 21 F1 1C 00 FA 00 00 00 40 00 04 08 01 00 00 00 00 04 0A 04 0A 03 0A 05 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 33 44 36 44 00 00 04 29 00 00 AD 5D 18 25 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   (WORD176)00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  Current media serial number 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (WORD200)00 00 00 00 00 00 00 00 00 00 00 00 3D 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 15 00 00 00 00 00 00 00 00 1F 10 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 E0 03 00 00 00 00 00 00 00 00 (WORD240)00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (WORD248)00 00 00 00 00 00 00 00 00 00 00 00 00 00 A5 4C   再读HBA MEM: READing. source addr=F7906000  dest addr=00017B08 now 256 byte data in hex is: 45 FF 30 CF 00 00 00 80 00 00 00 00 05 00 00 00     ――内容都没有变化 00 03 01 00 00 00 00 00 00 00 00 00 02 00 60 01 00 00 01 07 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 1E 31 00 1F 00 00 00 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   再读PORT0 MEM: READing. source addr=F7906100  dest addr=00017B08 now 256 byte data in hex is: 00 DC 09 00 00 00 00 00      00 E0 09 00 00 00 00 00   02 00 00 00          00 00 00 00    17 C0 00 00           00 00 00 00 IS有事件                            1100 0000 0001 0111 PIO Setup FIS Interrupt              CR=1,FR=1,FRE=1,ST=1 即收到PIO包   50 00 00 00           01 01 00 00      23 01 00 00       00 03 00 00 TFD,无ERR,无DRQ,无BSY 0101 0000 ERR=5   00 00 00 00    00 00 00 00    00 00 00 00    00 00 00 00 SERR无错误                    CI为0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     再读COMMAND LIST: READing. source addr=0009DC00  dest addr=00017B08 now 256 byte data in hex is: 05 00 01 00  00 02 00 00          00 87 01 00   00 00 00 00              显示已传输512字节    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     再读COMMAND TABLE: 原来的CFIS已经被冲掉了 READing. source addr=00018700  dest addr=00017B08 now 256 byte data in hex is: 30 20 30 30 20 30 30 20 30 30 20 0A 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 30 20 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   40 8A 01 00 00 00 00 00 00 00 00 00 E7 03 00 80    ――没有变化   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00       一、    总结 以上程序均在TC3.0下编译成功,DOS下运行。 这个工程花了我1个月左右的空闲时间,虽然只研究出皮毛,但还好程序读取成功了。希望有所帮助。 程序主要用于直接访问AHCI控制器,进而访问SATA硬盘来获取硬盘参数。 得出的结论是: 直接IO读出的硬盘参数,与“INT13H扩展”报告的参数是一致的,所以就用“INT13H扩展”就可以了,除非要获得硬盘型号、序列号等信息。 “INT13H传统”报告的HCS有经过转换,与分区表的参数是一致的。 如果是读写SATA硬盘的扇区,直接就用BIOS的“INT13H扩展”中断就可以了。 AHCI规范实在太复杂了,很多没看懂。不深入研究了,结束。  
  • 热度 17
    2015-4-23 17:20
    2154 次阅读|
    0 个评论
    int main( int argc, char *argv ,  *databuff;   unsigned long tmpADDR,  HBA_addr, PORT_addr;   BYTE tempbuff2 ,  *tablebuff;   HBA_CMD_TBL *myCMDTABLE;   HBA_CMD_HEADER myCMDHEADER;   FIS_REG_H2D  *myCFIS;   HBA_PRDT_ENTRY *myPRDT;   int myPORTnum;   int i;   unsigned char ctemp;        memset(tempbuff1, 0xAA, 1024);   memset(tempbuff2, 0, 1024);   memset(myCMDHEADER, 0, sizeof(HBA_CMD_HEADER));     //命令头CMDHEADER    myCMDHEADER.cfl= sizeof(FIS_REG_H2D)/sizeof(DWORD);  // Command FIS size   myCMDHEADER.w= 0;               // Read from device 从设备读   myCMDHEADER.prdtl = 1;      // PRDT entries count   1表示1个   tmpADDR=(unsigned long)FP_SEG(tempbuff2)*16+(unsigned long)FP_OFF(tempbuff2);   tmpADDR=(tmpADDR 0xffffff00) + 0x100 ;  //tmpADDR 要128字节对齐,这里取256字节   myCMDHEADER.ctba=tmpADDR;   tablebuff=MK_FP((unsigned int)(tmpADDR4), (unsigned int)(tmpADDR 0xf) );    // 一定要加(unsigned int),不然生成的地址为0   printf("tablebuff  SEG=%04X   OFF=%04X    FLAT ADDR=%08lX \n",  FP_SEG(tablebuff),  FP_OFF(tablebuff) , tmpADDR);   //命令表CMDTABLE   //命令包     myCMDTABLE=(HBA_CMD_TBL *)(tablebuff);          //注意“线性地址”与 “指针地址” 的不同,这里tablebuff(指针地址) 不能写成 tmpADDR(线性地址)   myCFIS=(FIS_REG_H2D *) (myCMDTABLE);   myCFIS-fis_type = 0x27;  //FIS_TYPE_REG_H2D   myCFIS-command =0xec ;  // 0xEC  ATA_CMD_IDENTIFY   myCFIS-device = 0;         // Master device   myCFIS-c = 1;              // Write command register  1表示这是一个命令     //PRDT ENTRY   myPRDT=(HBA_PRDT_ENTRY *)(myCMDTABLE-prdt_entry);   tmpADDR=(unsigned long)FP_SEG(tempbuff1)*16+(unsigned long)FP_OFF(tempbuff1);   tmpADDR=(tmpADDR 0xfffffff0) + 0x10 ;          //tmpADDR 要2字节对齐,这里取多一些   databuff=MK_FP((unsigned int)(tmpADDR4), (unsigned int)(tmpADDR 0xf) );    // 一定要加(unsigned int),不然生成的地址为0   printf("databuff  SEG=%04X   OFF=%04X    FLAT ADDR=%08lX \n",  FP_SEG(databuff),  FP_OFF(databuff) , tmpADDR);     myPRDT-dba= tmpADDR;   myPRDT-dbc1= 999;    //表示长度是1000字节   myPRDT-dbc2= 0;        myPRDT-i= 1;     printf("COMMAND HEADER in hex is:\n");   mydisplay( (unsigned char *)myCMDHEADER, 32 );   printf("COMMAND TABLE in hex is:\n");   mydisplay( (unsigned char *)myCMDTABLE, 144 );   printf("press a key...\n");getchar();     //读HBA MEM   if(argc3)   {      printf("you must input HBA addr, port number!");      return 0;   }     //得到命令行的HBA ADDR   if(strlen(argv ) != 8) { printf("HBA ADDR must be 8 chars long!"); return 0;}   HBA_addr=0;   for(i=0;i 8;i++)   {      argv = toupper(argv );      //转大写      ctemp=(unsigned char)argv ;        if (ctemp=0x30 ctemp=0x39)      {          ctemp=ctemp-0x30;      }      else if (ctemp=0x41 ctemp=0x46)      {          ctemp=ctemp-55;      }      else      { printf("HBA ADDR char error");       return 0;  }        HBA_addr+=((unsigned long)ctemp) (4*(7-i));   }     //得到命令行的PORT口   myPORTnum= atoi(argv );   if(myPORTnum0 || myPORTnum31 ) {printf("PORT NUMBER error!"); return 0; }   PORT_addr= HBA_addr + 256 + myPORTnum*128;   printf ("HBA addr=%08lXH  PORT addr=%08lXH \n",HBA_addr,  PORT_addr);     //读和显示MEM   memmove( HBA_addr ,   (unsigned long)FP_SEG(myHBAMEM)*16+(unsigned long)FP_OFF(myHBAMEM), 256 );  //源,目的,字节数(应为偶数)   memmove( PORT_addr ,  (unsigned long)FP_SEG(myHBAPORT)*16+(unsigned long)FP_OFF(myHBAPORT), 128 );  //源,目的,字节数(应为偶数)   printf("HBA MEM in hex is:\n");   mydisplay( (unsigned char *)myHBAMEM,  256);   printf("press a key...\n");getchar();     printf("PORT MEM in hex is:\n");   mydisplay( (unsigned char *)myHBAPORT,  128);   printf("press a key...\n");getchar();     //判断各个取值是否正常    if( !(myHBAMEM.ghc 31) ) { printf(" ERROR, AHCI NOT ENABLE "); return 0;}   if( myHBAMEM.bohc ) { printf(" ERROR, BIOS OR OS is controling HBA"); return 0;}   if( !( myHBAMEM.pi ((DWORD)1 myPORTnum) ) ) { printf(" ERROR, NO DEVICE ON THAT PORT"); return 0;}   if( myHBAPORT.clbu || myHBAPORT.fbu ) { printf(" ERROR, clbu or fbu ERROR"); return 0;}   if( (!myHBAPORT.clb) || (!myHBAPORT.fb) ) { printf(" ERROR, clb or fb ERROR"); return 0;}   if( myHBAPORT.is ) { printf(" ERROR, PxIS NOT ZERO"); return 0;}   if( myHBAPORT.serr ) { printf(" ERROR, PxSERR NOT ZERO"); return 0;}   if( myHBAPORT.tfd 0x89 ) { printf(" ERROR, ERR or DRQ or BSY NOT ZERO"); return 0;}                            //PxTFD.STS.BSY(bit7)=0,PxTFD.STS.DRQ(bit3)=0,PxTFD.STS.ERR(bit0)=0   if( (myHBAPORT.ssts 0x0f) !=3  ) { printf(" ERROR, PxSSTS.DET is not 3"); return 0;}      //PxSSTS.DET(bit3:0) = 3   if( (myHBAPORT.cmd 0x8000)   ) { printf(" ERROR, PxCMD.CR a command is running"); return 0;}    //PxCMD.CR(bit15)=0,FR(bit14)=0   if( (myHBAPORT.cmd 0x4000)   ) { printf(" ERROR, PxCMD.FR RFIS is receiving"); return 0;}   if( myHBAPORT.ci || myHBAPORT.sact   ) { printf(" ERROR, command slot is not all free"); return 0;}             //这里为简单起见,需SLOT全部空闲!即要使用SLOT0     //把COMMAND HEADER拷入SLOT   memmove( (unsigned long)FP_SEG(myCMDHEADER)*16+(unsigned long)FP_OFF(myCMDHEADER) ,   myHBAPORT.clb,  32 );  //源,目的,字节数(应为偶数)   printf("HAVE COPY COMMAND HEADER TO SLOT0     press a key...\n");   getchar();     //发送命令     myWRITEMEM_DWORD( PORT_addr+0x18,  myREADMEM_DWORD( PORT_addr+0x18) | 0x10   );  //设置PxCMD.FRE(bit4)=1  使能接收FIS    printf("HAVE SET PxCMD.FRE     press a key...\n");   getchar();   printf("PxCMD is %08lX\n",  myREADMEM_DWORD( PORT_addr+0x18));        myWRITEMEM_DWORD( PORT_addr+0x18,  myREADMEM_DWORD( PORT_addr+0x18) | 0x01   );  //设置PxCMD.ST(bit0)=1  使能命令运行   printf("HAVE SET PxCMD.ST      press a key...\n");   getchar();   printf("PxCMD is %08lX\n",  myREADMEM_DWORD( PORT_addr+0x18));     myWRITEMEM_DWORD( PORT_addr+0x38,  myHBAPORT.ci | 0x01   );  //写PxCI.CI相应位,让HBA发送命令。这里是SLOT0   //判断命令完成   delay(1000);  //延时1S   if( myREADMEM_DWORD(PORT_addr+0x38) )  {printf(" ERROR, PxCI.CI not return zero"); return 0; }  //PxCI.CI必须清零   if( myREADMEM_DWORD(PORT_addr+0x10) 0x40000000  ) {printf(" ERROR, PxIS.TFES is 1"); return 0; } //PxIS.TFES(bit30) 不能为1   //显示收到的数据   printf("data buff in hex is:\n");   mydisplay(databuff, 256);   printf("press a key...\n");getchar();    mydisplay(databuff+256, 256);     return 0; }  
  • 热度 16
    2015-4-23 17:18
    1877 次阅读|
    0 个评论
      十一、    直接读取SATA硬盘之四、访问AHCI控制器   (1)原理 需要参考INTEL的AHCI规范标准《serial-ata-ahci-spec-rev1-3-1》,非常重要。 网站osdev中,给出了AHCI的通俗介绍、访问AHCI控制器、SATA硬盘的程序,真的是帮助太大了,不然根本无法完成后面的程序。http://wiki.osdev.org/AHCI 内容实在是太多了,这里就不再说明了。   (2)直接读取SATA硬盘的程序――得到硬盘参数 在TC3.0下,HUGE模式编译。DOS运行。 ahci1.c : // TC3.0 下,HUGE模式,指针是4字节,MK_FP()是4字节,FP_SEG()是2字节   #include #include #include #include #include #include "read4g2.h"   #define BYTE unsigned char #define WORD unsigned int #define DWORD unsigned long     typedef struct tagFIS_REG_H2D {   // DWORD 0   BYTE   fis_type;  // FIS_TYPE_REG_H2D          FIS TYPE类型     BYTE   pmport:4;  // Port multiplier     表示第2个字节的4个bits   BYTE   rsv0:3;       // Reserved              表示第2个字节的3个bits   BYTE   c:1;       // 1: Command, 0: Control    表示第2个字节的1个bit     BYTE   command;   // Command register   BYTE   featurel;  // Feature register, 7:0     // DWORD 1   BYTE   lba0;      // LBA low register, 7:0   BYTE   lba1;      // LBA mid register, 15:8   BYTE   lba2;      // LBA high register, 23:16   BYTE   device;       // Device register     // DWORD 2   BYTE   lba3;      // LBA register, 31:24   BYTE   lba4;      // LBA register, 39:32   BYTE   lba5;      // LBA register, 47:40   BYTE   featureh;  // Feature register, 15:8     // DWORD 3   BYTE   countl;       // Count register, 7:0   BYTE   counth;       // Count register, 15:8   BYTE   icc;       // Isochronous command completion   BYTE   control;   // Control register     // DWORD 4   BYTE   rsv1 ;   // Reserved } FIS_REG_H2D;     typedef volatile struct tagHBA_PORT   // 每个PORT口的空间,长80H字节。 即对PORT0来说,是100~17FH空间 {   DWORD  clb;       // 0x00, command list base address, 1K-byte aligned   指向command list空间   DWORD  clbu;      // 0x04, command list base address upper 32 bits   DWORD  fb;    // 0x08, FIS base address, 256-byte aligned        指向Received FIS空间   DWORD  fbu;       // 0x0C, FIS base address upper 32 bits   DWORD  is;    // 0x10, interrupt status   DWORD  ie;    // 0x14, interrupt enable   DWORD  cmd;       // 0x18, command and status   DWORD  rsv0;      // 0x1C, Reserved   DWORD  tfd;       // 0x20, task file data   DWORD  sig;       // 0x24, signature   DWORD  ssts;      // 0x28, SATA status (SCR0:SStatus)   DWORD  sctl;      // 0x2C, SATA control (SCR2:SControl)   DWORD  serr;      // 0x30, SATA error (SCR1:SError)   DWORD  sact;      // 0x34, SATA active (SCR3:SActive)   DWORD  ci;    // 0x38, command issue   DWORD  sntf;      // 0x3C, SATA notification (SCR4:SNotification)   DWORD  fbs;       // 0x40, FIS-based switch control   DWORD  rsv1 ;  // 0x44 ~ 0x6F, Reserved   DWORD  vendor ; // 0x70 ~ 0x7F, vendor specific } HBA_PORT;       typedef volatile struct tagHBA_MEM         // 整个HBA内存空间 {   // 0x00 - 0x2B, Generic Host Control        //即00~2BH空间,Generic Host Control空间   DWORD  cap;       // 0x00, Host capability   DWORD  ghc;       // 0x04, Global host control   DWORD  is;    // 0x08, Interrupt status   DWORD  pi;    // 0x0C, Port implemented   DWORD  vs;    // 0x10, Version   DWORD  ccc_ctl;   // 0x14, Command completion coalescing control   DWORD  ccc_pts;   // 0x18, Command completion coalescing ports   DWORD  em_loc;       // 0x1C, Enclosure management location   DWORD  em_ctl;       // 0x20, Enclosure management control   DWORD  cap2;      // 0x24, Host capabilities extended   DWORD  bohc;      // 0x28, BIOS/OS handoff control and status     // 0x2C - 0x9F, Reserved   BYTE   rsv ;     // 0xA0 - 0xFF, Vendor specific registers   BYTE   vendor ;     // 0x100 - 0x10FF, Port control registers   //PORT口的空间   HBA_PORT   ports ;  // 1 ~ 32 } HBA_MEM;     typedef struct tagHBA_CMD_HEADER      // 每个command项(头,SLOT)的结构,长度32字节 {   // DW0   BYTE   cfl:5;     // Command FIS length in DWORDS, 2 ~ 16   BYTE   a:1;       // ATAPI   BYTE   w:1;       // Write, 1: H2D, 0: D2H   BYTE   p:1;       // Prefetchable     BYTE   r:1;       // Reset   BYTE   b:1;       // BIST   BYTE   c:1;       // Clear busy upon R_OK   BYTE   rsv0:1;       // Reserved   BYTE   pmp:4;     // Port multiplier port     WORD   prdtl;     // Physical region descriptor table length in entries     // DW1   volatile   DWORD  prdbc;     // Physical region descriptor byte count transferred     // DW2, 3   DWORD  ctba;      // Command table descriptor base address       128-byte aligned   指向 command table!!!   DWORD  ctbau;     // Command table descriptor base address upper 32 bits     // DW4 - 7   DWORD  rsv1 ;   // Reserved } HBA_CMD_HEADER;     typedef struct tagHBA_PRDT_ENTRY      // PRDT 入口,长度16字节 {   DWORD  dba;       // Data base address            2-byte aligned    指向data空间   DWORD  dbau;      // Data base address upper 32 bits   DWORD  rsv0;      // Reserved     // DW3   /*  TC3不支持DWORD的bit分组   DWORD  dbc:22;       // Byte count, 4M max   DWORD  rsv1:9;       // Reserved   DWORD  i:1;       // Interrupt on completion     */   WORD dbc1;   WORD dbc2:6;   WORD rsv1:9;   WORD i:1;       } HBA_PRDT_ENTRY;     typedef struct tagHBA_CMD_TBL         //command table 的结构 {   // 0x00   BYTE   cfis ;  // Command FIS     // 0x40   BYTE   acmd ;  // ATAPI command, 12 or 16 bytes     // 0x50   BYTE   rsv ;      // Reserved     // 0x80   HBA_PRDT_ENTRY    prdt_entry ;    // Physical region descriptor table entries, 0 ~ 65535 } HBA_CMD_TBL;     void    mydisplay(unsigned char *d,int n) {   int i,i2;   if (n=0) return;   i2=0;   for(i=0; i;   {      printf("%02X ",d );      i2++;      if(i2 =16 ) {i2=0; printf("\n");}   }     printf("\n"); }       unsigned long myREADMEM_DWORD(unsigned long addr) {   unsigned long lt;   memmove( addr , (unsigned long)FP_SEG()*16+(unsigned long)FP_OFF() , 4 );  //源,目的,字节数(应为偶数)   return lt; }     void myWRITEMEM_DWORD(unsigned long addr, unsigned long lt) {   memmove( (unsigned long)FP_SEG()*16+(unsigned long)FP_OFF() , addr, 4 );  //源,目的,字节数(应为偶数) }      
  • 热度 13
    2015-4-23 16:46
    1656 次阅读|
    0 个评论
      十、    直接读取SATA硬盘之(三)、DOS下访问高于1MB的内存空间   (1)原理 DOS下,CPU是处于 “实模式” ,不能访问高于1MB的内存。如何去访问4GB内存?比如这个F7906000H。那就必须要让CPU能切换到 “保护模式” 。 在保护模式下,地址的生成比较复杂,段是通过一系列被称之为“描述符表”的表所定义的。要扩大寻址范围就必须扩大“段描述符高速缓冲寄存器”中的界限值,但CPU在实模式下不能改变这些界限值,必须在保护模式下完成该操作。 有2种方法: l  一个是 DOS 程序中嵌入保护模式程序段 ,参见文章《DOS实方式下直接访问4GB内存》、《DOS操作系统下PCI板卡访问方法的研究与实现》等很多文章,还有: DOS下如何访问4G内存  http://www.cnblogs.com/kuwoyidai/archive/2010/07/14/1777527.html 在DOS实模式下直接存取4GB内存  http://www.docin.com/p-215328775.html 这个方法未试。 l  另一个是 采用INT 15H BIOS 中断调用 ,这里采用这种方法。重点参考文章《DOS下PCI卡内存映射空间的访问方法》,以及里面的程序。 INT 15H - SYSTEM - COPY EXTENDED MEMORY     AH = 87h     CX = number of words to copy (max 8000h)   ―――注意:长度是按WORD为单位     ES:SI - global descriptor table     GDT表   Return:     CF set on error     CF clear if successful     AH = status         00h source copied into destination         01h parity error         02h interrupt error         03h address line 20 gating failed         80h invalid command (PC,PCjr)         86h unsupported function (XT,PS30)   Format of global descriptor table: Offset Size     Description  00h   16 BYTEs   zeros  10h   WORD       source segment length in bytes (=2*CX-1 or greater)――长度限制  12h   3 BYTEs        24-bit(3字节) linear source address, low byte first  15h   BYTE       source segment access rights (=93h)  16h   WORD       zero  18h   WORD       destination segment length in bytes (=2*CX-1 or greater) ――长度限制  1Ah   3 BYTEs        24-bit(3字节) linear destination address, low byte first  1Dh   BYTE       destination segment access rights (=93h)  1Eh   18 BYTEs   zeros   上面对“描述符”的说明不是很清楚,可参考相关文章,比如: Global Descriptor Table    http://wiki.osdev.org/Global_Descriptor_Table     (2)可以读取内存的程序 read4g2.h : typedef struct Descriptorstruct    // 描述符结构   长8字节 {   unsigned int size ;     //段地址的长度限制,以字节计,可以=传输字节数   实际发现,设成0或1等,都不影响实际的传输字节数,即这个是无效的。   unsigned int base_low_word;   unsigned char base_mid_byte;   unsigned char attr1 ;   unsigned char attr2 ;   unsigned char base_high_byte; } Descriptor ;   typedef struct GDTStruct // GDT 表结构 {   Descriptor BlankDsc;     //空描述符   Descriptor GDTDsc;  //GDTR 的基地址和大小   Descriptor SrcDsc;       // 源段描述符   Descriptor DstDsc;       // 目标段描述符   Descriptor BiosCS;       // 代码段描述符   Descriptor BiosSS;       // 栈段描述符 } GDT;     GDT MoveGDT = {        //共48字节 {0 ,0 ,0 ,0 ,0 ,0} ,          //8字节0 {0 ,0 ,0 ,0 ,0 ,0} ,          //8字节0 {0 ,0 ,0 ,0x92 ,0x40 ,0} ,    // 源   00 00长度限制   00 00 00地址低3字节  92权限  40权限和长度限制   00地址高字节 {0 ,0 ,0 ,0x92 ,0x40 ,0} ,    // 目的 {0 ,0 ,0 ,0 ,0 ,0} ,          //8字节0 {0 ,0 ,0 ,0 ,0 ,0}            //8字节0 };     void memmove(unsigned long sou_addr ,unsigned long des_addr ,unsigned int num) // 数据移动函数  num为字节数 {   GDT mcb;   struct REGPACK reg;     MoveGDT.SrcDsc.base_low_word = sou_addr 0x0000ffff ;   MoveGDT.SrcDsc.base_mid_byte = sou_addr 16 ;   MoveGDT.SrcDsc.size = num;         //段地址长度限制,为字节数   MoveGDT.SrcDsc.base_high_byte = sou_addr 24 ;     MoveGDT.DstDsc.base_low_word = des_addr 0x0000ffff ;   MoveGDT.DstDsc.base_mid_byte = des_addr 16 ;   MoveGDT.DstDsc.size = num;         //段地址长度限制,为字节数   MoveGDT.DstDsc.base_high_byte = des_addr 24 ;     mcb=MoveGDT;        //另外赋一个GDT变量,因为INT15会改变这个变量值   reg.r_es = FP_SEG( mcb) ;   reg.r_si = FP_OFF( mcb) ;   reg.r_cx = num 1 ;    //长度是按WORD来算的,故要除以2。num=2或3,则CX=1,传输2个字节;num=0或1,则CX=0,不传输任何字节   reg.r_ax = 0x8700 ;   intr( 0x15 , reg ) ;   }     read4g2.c : #include stdio.h #include bios.h #include stdlib.h #include conio.h #include dos.h #include "read4g2.h"   int main(int argc, char *argv ;     des_addr=(unsigned long)FP_SEG(databuf)*16+(unsigned long)FP_OFF(databuf);     if(argc2)   {      printf("you must input args!");      return 0;   }     if(strlen(argv ) != 8) { printf("ADDR must be 8 chars long!"); return 0;}     sou_addr=0;   for(i=0;i 8;i++)   {      argv = toupper(argv );      ctemp=(unsigned char)argv ;        if (ctemp=0x30 ctemp=0x39)      {          ctemp=ctemp-0x30;      }      else if (ctemp=0x41 ctemp=0x46)      {          ctemp=ctemp-55;      }      else      { printf("ADDR char error"); return 0; }        sou_addr+=((unsigned long)ctemp) (4*(7-i));     }     //以下分2部分,读、写 if (argc2) goto fillmemory;     printf ("READing. source addr=%08lX  dest addr=%08lX \nnow 256 byte data in hex is:\n",sou_addr,des_addr);     memmove( sou_addr , des_addr , 512);     i2=0;   for(i=0; i256; i++)   {      printf("%02X ",databuf );      i2++;      if(i2 =16 ) {i2=0; printf("\n");}   }     return 0;       fillmemory:   if( strcmp(argv ,"fill") ) {printf("error param fill\n"); return 0;}   if(argc5 ) {printf("error no data\n"); return 0;}   cdata=0;   for(i=0;i 2;i++)   {      argv = toupper(argv );      ctemp=(unsigned char)argv ;        if (ctemp=0x30 ctemp=0x39)      {          ctemp=ctemp-0x30;      }      else if (ctemp=0x41 ctemp=0x46)      {          ctemp=ctemp-55;      }      else      { printf("data char error"); return 0; }        cdata+=ctemp (4*(1-i));     }     i3= atoi(argv );   if(i30 || i31000 ) {printf("length error!"); return 0; }   for(i=0; i1000; i++)   {      databuf =cdata;      //cdata++;   }       ltemp=sou_addr;   sou_addr=des_addr;   des_addr=ltemp;   printf ("WRITing. source addr=%08lX  dest addr=%08lX  with data %02X   length %d\n",sou_addr,des_addr,cdata,i3);     memmove( sou_addr , des_addr , i3);     return 0;    }     (3)说明 用这个INT15H方法,实际测试发现,描述符结构中,段地址的长度限制设成0或1等等,都不影响实际的传输字节数,即这个是无效的。 CX是WORD的数量,num=2或3,则CX=1,传输2个字节;num=0或1,则CX=0,不传输任何字节。 即每次传输的数据单位只能是以 WORD 计的!! 加载或不加载HIMEM.SYS,均不影响。也不用人工进行打开A20地址线操作。   (4)DOS下运行 读取SATA AHCI控制器的内存空间F7906000H: read4g2 F7906000 如果要填充某一段内存为0xff,长256字节:read4g2 00a00000 fill ff 256      
  • 热度 14
    2015-4-23 16:45
    1725 次阅读|
    0 个评论
    九、    直接读取SATA硬盘之(二)、PCI设备枚举、32位端口的访问、找到AHCI控制器的内存空间地址   (1)PCI设备枚举 SATA AHCI控制器是一个挂在PCI总线上的设备,通过对PCI设备枚举,可以找到这个设备,然后得到它的配置空间信息。 方法是直接对 IO端口号CF8H、CFCH 进行访问。原理是“总线号、设备号、功能号”这三者确定了一个“PCI功能设备”,其实是读这个设备的00H号寄存器,字节偏移地址是00处,这里有Device ID和Vendor ID,通过判断这个ID是否正常,来判断是否存在一个PCI设备。 很多文章有介绍,比如:《dos下枚举 pci设备》(http://blog.csdn.net/zyl910/article/details/858349)   问难的难点是: CF8H、CFCH端口是32位的 ,即访问它们的数据应是32位(4字节)的,而DOS下的汇编、TC都只有8位、16位端口访问。 解决方法有2个: 一个是 在程序中插入汇编 ,采用32位指令前缀66H,这样就能执行32位指令。可参考上面的文章,以及《DEBUG下使用32位指令的技术》。 另一个是 采用PCI BIOS中断 ,中断号1AH。可参见上面的文章。这里采用这种方法,用 WORD 方式来访问PCI配置空间。 INT 1A - PCI BIOS v2.0c+ - READ CONFIGURATION WORD AX = B109h BH = bus number BL = device/function number (bits 7-3 device, bits 2-0 function) DI = register number (0000h-00FFh, must be multiple of 2) (see #00878) ――偏移量(以字节计) Return: CF clear if successful    CX = word read ―― 一次读出2个字节,即1个WORD CF set on error AH = status (00h,87h) (see #00729) EAX, EBX, ECX, and EDX may be modified all other flags (except IF) may be modified     (2)程序 从上面的文章中的程序改的,findpci.c:   /* File:    epcib.c Name:    使用PCI BIOS来枚举PCI设备 Author:   zyl910 Blog:    http://blog.csdn.net/zyl910/ Version:  V1.0 Updata:   2006-6-30 */   #include stdio.h #include conio.h #include dos.h   typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD;     /* PCI设备索引。bus/dev/func 共16位,为了方便处理可放在一个WORD中 */ #define PDI_BUS_SHIFT  8 #define PDI_BUS_SIZE   8 #define PDI_BUS_MAX    0xFF #define PDI_BUS_MASK   0xFF00   #define PDI_DEVICE_SHIFT  3 #define PDI_DEVICE_SIZE   5 #define PDI_DEVICE_MAX    0x1F #define PDI_DEVICE_MASK   0x00F8   #define PDI_FUNCTION_SHIFT  0 #define PDI_FUNCTION_SIZE   3 #define PDI_FUNCTION_MAX    0x7 #define PDI_FUNCTION_MASK   0x0007   #define MK_PDI(bus,dev,func) (WORD)((busPDI_BUS_MAX)PDI_BUS_SHIFT | (devPDI_DEVICE_MAX)PDI_DEVICE_SHIFT |(funcPDI_FUNCTION_MAX) )     int main(void) { int bus, dev, func; int i; union REGS regs; WORD wAddr; FILE *hF; char szFile ;   printf("\n"); printf("Bus#\tDevice#\tFunc#\tVendor\tDevice\tClass\tIRQ\tIntPin\n");   /* 枚举PCI设备 */ for(bus = 0; bus = PDI_BUS_MAX; ++bus) // BUS编号00~FFH,256个 {   for(dev = 0; dev = PDI_DEVICE_MAX; ++dev)  // 设备编号00~1FH,32个   {      for(func = 0; func = PDI_FUNCTION_MAX; ++func)   //功能编号00~07H,8个      {         /* 计算地址 */         wAddr = MK_PDI(bus, dev, func);    //转换成16BIT地址                 /* 获取厂商ID */         regs.x.ax = 0xB109;       // PCI BIOS v2.0c+ - READ CONFIGURATION WORD         regs.x.bx = wAddr;        // BH = bus number                                   // BL = device/function number (bits 7-3 device, bits 2-0 function)         regs.x.di = 0;            // DI=register number=00H,即取出“PCI Configuration Data”的00H处的值,00H处的值是 Vendor ID         regs.x.cx = 0xFFFF;       // 非法的Vendor ID   ,也可以不写这句         int86(0x1A, regs, regs);   //返回 CX = word read,如果是非法Vendor ID,则会返回CX=0xFFFF              /* 判断设备是否存在。FFFFh是非法厂商ID */         if (regs.x.cx != 0xFFFF)     //如果Vendor ID合法         {              /* bus/dev/func */              printf("%2.2XH\t%2.2XH\t%1XH\t", bus, dev, func);                       /* Vendor */              printf("%4.4XH\t", regs.x.cx);                       /* Device */              regs.x.ax = 0xB109;    // PCI BIOS v2.0c+ - READ CONFIGURATION WORD              regs.x.bx = wAddr;                  regs.x.di = 2;         // Device ID 。DI=register number=02H,即取出“PCI Configuration Data”的02H处的值,02H处的值是 Device ID              int86(0x1A, regs, regs);              printf("%4.4XH\t", regs.x.cx);                       /* Class Code */              regs.x.ax = 0xB109; // PCI BIOS v2.0c+ - READ CONFIGURATION WORD              regs.x.bx = wAddr;              regs.x.di = 0xA; // 取出Class/SubClass 值              int86(0x1A, regs, regs);              printf("%4.4XH\t", regs.x.cx);                       /* IRQ/intPin */              regs.x.ax = 0xB109; // PCI BIOS v2.0c+ - READ CONFIGURATION WORD              regs.x.bx = wAddr;              regs.x.di = 0x3C; // 取出IRQ/IntPin 值              int86(0x1A, regs, regs);              printf("%d\t", (BYTE)regs.x.cx);              printf("%d", (BYTE)(regs.x.cx8));                       printf("\n");                       /* 写文件 */              sprintf(szFile, "PCI%2.2X%2.2X%X.bin", bus, dev, func);              hF = fopen(szFile, "wb");           //打开文件              if (hF != NULL)              {                 /* 256字节的PCI配置空间 */                 for (i = 0; i 0x100; i += 2)                 {                      /* Read */                      regs.x.ax = 0xB109; // PCI BIOS v2.0c+ - READ CONFIGURATION WORD                      regs.x.bx = wAddr;                      regs.x.di = i;                      int86(0x1A, regs, regs);                                      /* Write */                      fwrite(regs.x.cx, 2, 1, hF);                 }                 fclose(hF);              }         }        }     } }   return 0; }       (3)DOS下运行得到的结果: Bus#     Device#        Func#  Vendor     Device     Class      IRQ     IntPin 00H      1FH        2H      8086H      1E03H      0106H      10      2      即INTEL7 SATA AHCI CONTROLLER   得到的“设备配置空间”的内容: 8680031E0700B0020401060100000000 B1F00000A1F0000091F0000081F00000 61F00000006090F7000000004310AC10 0000000080000000000000000A020000 00800080000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01A80340080000000000000000000000   05700000000000000000000000000000 603A05858301003A08425C0100000000 E00000003900000012B0100048000000 13000603000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 0000000000000000870F040800000000 (其余为00)     分析如下: “设备配置空间”数据的0x10偏移处: B1 F0 00 00    第0BIT的“1”表示映射到I/O空间,即这是IO地址,0xF0B0 A1 F0 00 00   91 F0 00 00    81 F0 00 00 61 F0 00 00 00 60 90 F7    第0BIT的“0”则表示映射到内存空间,即这是 内存地址F7906000H,这个就是AHCI控制器的内存空间地址!!   在win7的设备管理器上,看SATA AHCI控制器资源是: IO范围 F0B0-F0B7, ―― 这几个是端口地址,如果在BIOS中设置成“IDE兼容”模式,应该就可以像端口1F0H~1F7H那样用,没试过。 F0A0-F0A3, ―― 这几个是端口地址,如果在BIOS中设置成“IDE兼容”模式,应该就可以像端口3F6H~3F7H那样用,没试过。 F090-F097, F080-F083, F060-F07F 内存 00000000F7906000 - 00000000F79067FF ――内存空间地址也是 F7906000H IRQ 0x13   访问这个内存空间 F7906000H ,就是对AHCI控制器进行控制。 难题来了,这个内存地址是高于1MB的,DOS下如何访问???  
相关资源