显示硬盘信息【下】

     在上篇中,在填充完寄存器之后也不等待硬盘中断处理程序结束就直接返回了,在这里我们就需要等待,在Disp_HD_Info调用Wait_Int函数:

    kernel/hd.c

Code:
  1. /*----------------------------------------------------------------------Wait_Int    
  2.     等待硬盘中断程序执行完毕  
  3. */  
  4. static void Wait_Int()   
  5. {   
  6.     Message m;   
  7.     m.msg_type = HARD_INT;   
  8.     Send_Receive_Shell(RECEIVE,INTERRUPT,&m);   
  9. }  

    注意这里修改了MSG_Receive函数,新增加的代码如下:

    kernel/ipc.c

Code:
  1. /* 如果在等待一个外中断的消息 */  
  2. if((m->msg_type == HARD_INT) && (send_pid == INTERRUPT))   
  3. {   
  4.     /* 如果该中断在此之前已经执行完毕,则把标志重置为0返回 */  
  5.     if(caller->has_int_msg == 1)   
  6.     {   
  7.         caller->has_int_msg = 0;   
  8.         return;   
  9.     }   
  10.     /* 否则则阻塞当前进程,并重新调度 */  
  11.     else  
  12.     {   
  13.         caller->ipc_status |= RECEIVING;   
  14.         caller->ipc_status &= ~NO_BLOCK;    
  15.         Schedule();   
  16.         return;   
  17.     }   
  18. }  

    同时修改硬盘中断处理函数:

    kernel/hd.c

Code:
  1. /*-------------------------------------------------------------Hard_Disk_Handler  
  2.     硬盘中断处理程序  
  3. */  
  4. static void Hard_Disk_Handler(int int_vec_no)   
  5. {   
  6.     In_Byte(REG_STATUS);    /* 必须从状态寄存器清空状态值 */  
  7.        
  8.     /* 处理在等待中断结束的进程 */  
  9.     PCB *sender = PCB_Table + PROC_HD_PID;  /* 明确指定硬盘驱动进程 */  
  10.     sender->has_int_msg = 1;                /* 代表已经处理过 */  
  11.     /* 使硬盘驱动进程解除阻塞 */  
  12.     sender->ipc_status &= ~RECEIVING;          
  13.     sender->ipc_status |= NO_BLOCK;   
  14. }  

    用到的相关宏如下:

    include/ipc.h

Code:
  1. #define INTERRUPT       -3      /* 由中断处理程序发送或者接收的消息 */  

    include/const.h

Code:
  1. #define HARD_INT                    2           /* 表示等待外中断功能号 */  

    在PCB中添加has_int_msg字段:

    include/proc.c

Code:
  1. int has_int_msg;                    /* 表示是否中断处理程序是否结束 */  

    在初始化PCB时也别忘了这个字段,在Init_PCB函数中添加:

    kernel/proc.c

Code:
  1. p_Cur_PCB->has_int_msg = 0;  

    OK,我们现在可以把硬盘信息从端口读到一个缓冲区中,查阅资料得到这个信息是256个word,因此就是512字节,我们先定义一个缓冲区,再在Disp_HD_Info函数中追加调用一个函数把数据写到这个缓冲区中:

    kernel/hd.c

Code:
  1. /* 内部数据声明 */  
  2. static u8 hd_buf[512];  /* 硬盘信息缓冲区 */  
  3. ...   
  4. //Disp_HD_Info函数末追加   
  5. Read_Port_2_Buffer(REG_DATA,hd_buf,256);  /* 把硬盘信息读出来放到缓冲区中 */  

    这个函数用汇编写的,因为在读端口时有一点与以前有些不同:

    lib/lib_kernel_in_asm.asm:

Code:
  1. global Read_Port_2_Buffer   
  2. ...   
  3. ;-------------------------------------------------------------Read_Port_2_Buffer   
  4. Read_Port_2_Buffer:   
  5. ;insw为串输入指令,以字单位,该指令的功能是从dx指定的端口读入一个字节   
  6. ;到es:di指定的内存单元中   
  7. ;由于数据以1个字为一组的,所以必须一次读1个字   
  8.        
  9.     mov edx,[esp + 4]       ;端口号送edx   
  10.     mov edi,[esp + 8]       ;缓冲区偏移送edi   
  11.     mov ecx,[esp + 12]      ;要复制的字的个数送ecx   
  12.        
  13.     cld                     ;clear df   
  14.     rep insw   
  15.     ret   

    在include/proto.h添加声明,过程略。

    OK,数据已经存在于我们的缓冲区了,由于数据太多,我们要有选择的输出,首先在Disp_HD_Info函数追加:

    kernel/hd.c

Code:
  1. Show_HD_Info(hd_buf);   /* 选择一些信息实现出来 */  

    Show_HD_Info函数体如下,注释得还可以了:

    kernel/hd.c

Code:
  1. /*------------------------------------------------------------------Show_HD_Info  
  2.     把缓冲区中的数据有选择的输出  
  3. */  
  4. static void Show_HD_Info(void *hd_buf)   
  5. {   
  6.     u16 *buf = (u16*)hd_buf;   
  7.     char tmp[60];   /* 临时串的BUFFER */  
  8.     int i,j;   
  9.        
  10.     /*   
  11.         我们想显示硬盘的序列码和模式,这里以一个结构来组织相关信息  
  12.         看起来有点拐弯抹角,但如果要显示多个占有多个字的信息项  
  13.         这样可以有效减少重复代码和方便扩展  
  14.         序列码起始字号为10,占用10个字,说明串为...  
  15.         模式名起始字号为27,占用10个字,说明串为...  
  16.     */  
  17.     HD_Str_Info str_info[2] = {   
  18.                                {10,10,"Hard Disk Serial Num:"},   
  19.                                {27,20,"Hard Disk Model:"}   
  20.                               };   
  21.                                  
  22.     for(i = 0;i < sizeof(str_info) / sizeof(str_info[0]);i++)   
  23.     {   
  24.         /* 指向每个数据项的首个数据块 */  
  25.         char *p = (char*)(buf + str_info[i].offset);   
  26.         /* 把串转移到临时缓冲区中 */  
  27.         for(j = 0;j < str_info[i].num;j++)   
  28.         {   
  29.             /*   
  30.                 这里注意,数据是以字来组织,而一个字符为一个字节  
  31.                 这里是小端存储,也就是遵低低高高原则  
  32.                 所以在一个字中高8位代表的字符实际顺序上在低8位字符之后  
  33.             */  
  34.             tmp[j * 2 + 1] = *p++;   
  35.             tmp[j * 2] = *p++;   
  36.         }   
  37.         tmp[j * 2] = '/0';  /* 置串结束符 */  
  38.         Printf("%s%s/n",str_info[i].label,tmp);     /* 连同说明串打印出来 */  
  39.     }   
  40.        
  41.     /* 如果buf[49]的第9位为1,表示支持LBA模式 */  
  42.     Printf("LBA supported:%s/n",(buf[49] & 0x200) ? "YES" : "NO");   
  43.        
  44.     /* 如果buf[83]的第10位为1,表示支持LBA的48位寻址模式 */  
  45.     Printf("LBA48 supported:%s/n",(buf[83] & 0x400) ? "YES" : "NO");   
  46.        
  47.     /* buf[60]为扇区总数的低16位,buf[61]为扇区总数的高16位 */  
  48.     int sector_num = ((int)buf[61] << 16) + buf[60];   
  49.     /* 单位转换为MB打印出来 */  
  50.     Printf("Hard Disk Size:%dMB/n",sector_num * 512 / 1000000);   
  51. }   

    其中用到的结构如下:

    include/hd.h

Code:
  1. /* 硬盘信息占用多个数据块的信息项 */  
  2. typedef struct s_hd_str_info   
  3. {   
  4.     int offset;     /* 某数据项的首个数据块的偏移 */  
  5.     int num;        /* 某数据项占用的数据块的总数 */  
  6.     char *label;    /* 某数据块的说明 */  
  7. }HD_Str_Info;  

    OK,make,bochs,结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值