无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站广告联系 微信:wuyouceo QQ:184822951
查看: 11987|回复: 38
打印 上一主题 下一主题

[原创首发]HPA初步认识与分析

[复制链接]
1#
发表于 2008-7-28 11:49:29 | 显示全部楼层
原帖由 天风 于 2008-7-28 10:37 发表
照抄一个给需要的朋友:
设置硬盘最大可读取扇区源码:
======================================
/* setmax.c - aeb, 000326 - use on 2.4.0test9 or newer */
/* I ...

这个资料有点老了,新的需要用READ_NATIVE_MAX_ADDR_EXT、SET_MAX_ADDR_EXT
并且LBA地址也变成48位了。
使用SET_MAX_ADDR_EXT还是SET_MAX_ADDR,要对get_identity取得的参数块中的id[83]和id[86]进行判断。
原来的两个函数要改一下:

  1. #define READ_NATIVE_MAX_ADDR_EXT  0x27
  2. #define SET_MAX_ADDR_EXT                0x37
  3. #define TASKFILE_CMD_REQ_NODATA    0
  4. #define TASKFILE_XFER_METHOD_NONE 0
  5. static __u64 get_native_max_address(int fd,__u16 **id_p)
  6. {
  7.       struct hdio_taskfile r;
  8.       __u16 *id;
  9.       *id_p=id=get_identify_data(fd,*id_p);
  10.       if(id&&((id[83]&0xc400)==0x4400)&&(id[86]&0x0400)){
  11.               memset(&r,0,sizeof(r));
  12.               r.cmd_req=TASKFILE_CMD_REQ_NODATA;
  13.               r.xfer_method=TASKFILE_XFER_METHOD_NONE;
  14.               r.lob.command=READ_NATIVE_MAX_ADDR_EXT;
  15.               r.lob.dev=0x40;
  16.               taskfile_std_flags(&r,1);
  17.               if(!do_taskfile_cmd(fd,&r,10))
  18.                       return((__u64)((r.hob.lbah<<16)|(r.hob.lbam<<8)|r.hob.lbal)|((r.lob.lbah<<16)|(r.lob.lbam<<8)|r.lob.lbal))+1;
  19.               perror ("读取硬盘真实容量失败!");
  20.       }
  21.       memset(&r,0,sizeof(r));
  22.       r.cmd_req=TASKFILE_CMD_REQ_NODATA;
  23.       r.xfer_method=TASKFILE_XFER_METHOD_NONE;
  24.       r.lob.command=READ_NATIVE_MAX_ADDR;
  25.       r.lob.dev=0x40;
  26.       taskfile_std_flags(&r,0);
  27.       if (!do_taskfile_cmd(fd,&r,10))
  28.               return ((r.lob.lbah<<16)|(r.lob.lbam<<8)|r.lob.lbal)+1;
  29.       perror ("读取硬盘真实容量失败!");
  30.       return 0;
  31. }
  32. static void set_max_address (int fd, __u16 **id_p, __u64 secs, int nonvolat)
  33. {
  34.       struct hdio_taskfile r;
  35.       __u16 *id;
  36.       __u64 addr=secs-1;
  37.       *id_p=id=get_identify_data(fd,*id_p);
  38.       if(id&&((id[83]&0xc400)==0x4400)&&(id[86]&0x0400)){
  39.               memset(&r,0,sizeof(r));
  40.               r.cmd_req=TASKFILE_CMD_REQ_NODATA;
  41.               r.xfer_method=TASKFILE_XFER_METHOD_NONE;
  42.               r.lob.command=SET_MAX_ADDR_EXT;
  43.               r.lob.feat=0;
  44.               r.lob.dev=0x40;
  45.               r.lob.nsect=nonvolat ? 1 : 0;
  46.               r.lob.lbal=addr&0xff;
  47.               r.lob.lbam=(addr>>8)&0xff;
  48.               r.lob.lbah=(addr>>16)&0xff;
  49.               r.hob.lbal=(addr>>24)&0xff;
  50.               r.hob.lbam=(addr>>32)&0xff;
  51.               r.hob.lbah=(addr>>40)&0xff;
  52.               taskfile_std_flags(&r,1);
  53.               if(!do_taskfile_cmd(fd,&r,10))
  54.                       return;
  55.               perror ("设置HPA失败!");
  56.       }
  57.       if(addr&0xfffffffff0000000LLU){
  58.               fprintf(stderr,"不支持LBA28!\n");
  59.               return;
  60.       }
  61.       memset(&r,0,sizeof(r));
  62.       r.cmd_req=TASKFILE_CMD_REQ_NODATA;
  63.       r.xfer_method=TASKFILE_XFER_METHOD_NONE;
  64.       r.lob.command=SET_MAX_ADDR;
  65.       r.lob.feat=0;
  66.       r.lob.dev=0x40|((addr>>24)&0x0f);
  67.       r.lob.nsect=nonvolat ? 1 : 0;
  68.       r.lob.lbal=addr&0xff;
  69.       r.lob.lbam=(addr>>8)&0xff;
  70.       r.lob.lbah=(addr>>16)&0xff;
  71.       taskfile_std_flags(&r,0);
  72.       if (do_taskfile_cmd(fd,&r,10))
  73.               perror ("设置HPA失败!");
  74.       return;
  75. }
复制代码
***addr的单位是扇区不是字节***
下面是LBA28和LBA48对照表,LBA28只有左边部分(字节),LBA48扩展成字,并且bit24~27也不放原来LBA28的那个位置了(原来在dev reg的低4位)。ATA命令放在这个表下面的一个字节/字。

另外,为了避免被病毒利用加口令部分俺就不提供了:)其实还有一个比较麻烦的是要先取得硬盘I/O口基址,这个要从PCICFG取得。

[ 本帖最后由 netwinxp 于 2008-8-1 08:56 编辑 ]

评分

参与人数 1无忧币 +40 收起 理由
lintel + 40 精品文章

查看全部评分

回复

使用道具 举报

2#
发表于 2008-7-28 14:38:31 | 显示全部楼层
#include <linux/hdreg.h>
一看不就知道了:)
回复

使用道具 举报

3#
发表于 2008-7-29 09:10:19 | 显示全部楼层
原帖由 阿文 于 2008-7-28 23:31 发表
LINUX下用C写,有点意思
我认为这一类东西,还是汇编比较底层一些,当然C也可以
HPA的生成程序,我也反汇编过了,用了好几个中断,端口之类的,而且还有的参数还未查明,关键的部位。
INT 0FH
INT 58H
...

这些中断只是居于ROM的程序为了修改int 19h而加载做的改动,其实非ROM方式最多只需要使用到INT 13H,其实不用也可以。

简单地说ATA命令就是把上面我提到的那个数据块格式把数据分别送到1F1~1F6,然后把ATA命令送往1F7,就算执行完毕(LBA48分两次传送,方式是FIFO)。然后再从1F0口存取数据(要多次),从1F7口读取状态,并不断监视1F7口读取的状态,其中1F3~1F5(部分1F6)传送所需要访问的地址,早期的硬盘接受CHS地址,剩下的就要用LBA地址了,LBA地址是从0开始的(也就是MBR相对LBA地址来说是0),至于每个ATA命令需要哪些参数,和具体参数的含义可以参考ATA标准文档。
通过向3F6口选择通道,1F6口选择主从设备(A0=Master,B0=Slave)。

比如我们要读取主通道Master设备上的MBR可以通过下面来完成(如果用程序的话,要记得加入延迟):
  1. debug
  2.      -o 3F6 04   ;设置通道
  3.      -o 3F6 00
  4.      -i 1F7         ;50H=硬盘存在
  5.      -o 1F2 1     ;读1个扇区
  6.      -o 1F3 0     ;设置开始的LBA地址
  7.      -o 1F4 0
  8.      -o 1F5 0
  9.      -o 1F6 e0    ;选择Master设备,该字节的各位含义参见ATA文档
  10.      -o 1F7 20    ;发送PIO读命令
  11.      -i 1F7          ;58H=硬盘数据准备好
  12.      -a 100
  13.      mov dx,1F0h ;数据口
  14.      mov si,1000h;存放数据的开始地址,如果选择DMA来自动传送,不要让结束地址越过FFFF。
  15.      mov cx,200h ;512字节
  16. L1: in al,dx
  17.      mov [si],al
  18.      inc si
  19.      loop L1
  20.      int 3
  21.      -g
复制代码
以上假设磁盘控制器的数据口基址为1F0。

[ 本帖最后由 netwinxp 于 2008-8-1 12:14 编辑 ]
回复

使用道具 举报

4#
发表于 2008-7-31 12:27:09 | 显示全部楼层
没下文啦?好像对此感兴趣的人不是太多:(
回复

使用道具 举报

5#
发表于 2008-8-1 10:32:02 | 显示全部楼层
IDENTIFY返回的信息里面的word82 bit10是是否支持HPA的标志。word83 bit8是"SET_MAX security extension"是否支持的标志,bit10表示是否支持LBA48。

[ 本帖最后由 netwinxp 于 2008-8-1 10:38 编辑 ]
回复

使用道具 举报

6#
发表于 2008-12-10 17:24:59 | 显示全部楼层
通过读取PCICFG的硬盘控制器的对应的数据,详细建议参考linux的磁盘控制器驱动。
回复

使用道具 举报

7#
发表于 2010-2-20 23:26:05 | 显示全部楼层
友情提示:对于大于137G且支持HPA的硬盘请慎重使用天风提供的那个setmax.c,否则硬盘很可能会被锁定成137G。
个人推荐使用hdparm_8(linux滴)或更新版本

[ 本帖最后由 netwinxp 于 2010-2-20 23:29 编辑 ]
回复

使用道具 举报

8#
发表于 2010-2-21 09:29:51 | 显示全部楼层
对,并且最好是使用Phonix的BIOS。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2024-5-3 08:11

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表