流水账如下:
1,建立各进程的pid的宏,方便阅读。
proc.h中添加:
- /* 各进程的进程号 */
- #define PROC_A_PID 0
- #define PROC_B_PID 1
- #define PROC_C_PID 2
- #define PROC_TTY_PID 3
- #define PROC_MSG_PID 4
- #define PROC_FS_PID 5
- #define PROC_HD_PID 6
2,建立一个用户级的文件系统进程,暂时只干一件事儿,就是向处理硬盘驱动消息的系统进程发一个消息,表示要打印硬盘的有关信息,然后死循环。添加一个进程的步骤这里就不赘述了,以下同略。
kernel/fs.c
- /*
- By Marcus Xing
- kernel/fs.c
- 与文件系统有关的代码
- */
- #include "type.h"
- #include "const.h"
- #include "console.h"
- #include "tty.h"
- #include "protect.h"
- #include "proc.h"
- #include "ipc.h"
- #include "proto.h"
- /*--------------------------------------------------------------Proc_File_System
- 文件系统进程的执行体
- */
- void Proc_File_System()
- {
- Message m;
- m.msg_type = HD_INFO;
- Send_Receive_Shell(BOTH,PROC_HD_PID,&m);
- Milli_Delay(3000);
- Send_Receive_Shell(BOTH,PROC_HD_PID,&m);
- Printf("PROC FS LOOP/n");
- while(1);
- }
其中用到的HD_INFO宏在const.h中定义:
const.h
- #define HD_INFO 1 /* 显示硬盘信息的功能号 */
3,建立一个系统进程,专门用来接收发送与硬盘有关的消息,在这里接收FS进程发送的消息,显示有关的硬盘信息。细节都写在注释里了。在hd.c中添加:
hd.c
- /*----------------------------------------------------------------Init_Hard_Disk
- 初始化硬盘驱动
- 显示硬盘个数,打开硬盘中断
- */
- void Init_Hard_Disk()
- {
- u8 *hd_num = (u8*)0x475; /* BIOS会在0x475地址处写入硬盘数 */
- /* 显示之 */
- Disp_Color_Str("Driver Num is ",Make_Color(RED,BLACK));
- Disp_Int(*hd_num);
- Disp_Str("/n");
- /* 设置发生硬盘中断的处理函数 */
- IRQ_Handler_Table[AT_WINI_IRQ] = Hard_Disk_Handler;
- /* 由于硬盘中断在从片,所以必须先打开级联中断 */
- Enable_IRQ(CASCADE_IRQ);
- Enable_IRQ(AT_WINI_IRQ);
- }
- /*----------------------------------------------------------------Proc_Hard_Disk
- 硬盘驱动程序进程,以消息为接口
- */
- void Proc_Hard_Disk()
- {
- Message m;
- while(1)
- {
- Send_Receive_Shell(RECEIVE,ANY,&m);
- int src = m.src_proc_pid;
- switch(m.msg_type)
- {
- case HD_INFO:
- //Printf("HD_INFO MESSAGE RECEIVED!");
- Disp_HD_Info();
- break;
- default:
- Panic("hd.c:UNKNOWN MESSAGE TYPE");
- break;
- }
- Send_Receive_Shell(SEND,src,&m);
- }
- }
- /*-------------------------------------------------------------Hard_Disk_Handler
- 硬盘中断处理程序
- */
- static void Hard_Disk_Handler(int int_vec_no)
- {
- In_Byte(REG_STATUS); /* 必须从状态寄存器清空状态值 */
- Printf("HARD_DISK_HANDLER/n");
- }
- /*------------------------------------------------------------------Disp_HD_Info
- 显示硬盘信息功能函数
- */
- static void Disp_HD_Info()
- {
- HD_Command hd_cmd;
- /* 把命令结构的各字段填充为0 */
- u8 *p = (u8*)&hd_cmd;
- int i = 0;
- for(;i < sizeof(HD_Command);i++)
- {
- *p = 0;
- }
- /* 填充相应的命令 */
- hd_cmd.device = MAKE_DEVICE_REG(0,0,0);
- hd_cmd.command = CMD_INFO;
- HD_Cmd_Out(&hd_cmd); /* 开始填充寄存器 */
- /* 这里先不等待硬盘中断返回,因为我们暂不打印硬盘信息 */
- }
- /*--------------------------------------------------------------------HD_Cmd_Out
- 填充硬盘驱动器各个寄存器的功能函数
- */
- static void HD_Cmd_Out(HD_Command *hd_cmd)
- {
- /* 状态寄存器的最高位为0才可继续进行 */
- do
- {
- u8 cur_status = In_Byte(REG_STATUS);
- if((cur_status & 0x80) == 0)
- {
- break;
- }
- Milli_Delay(100);
- }while(1);
- Out_Byte(REG_DEVICE_CTL,0); /* 使能中断响应 */
- /* 填充寄存器 */
- Out_Byte(REG_FEATURES,hd_cmd->features);
- Out_Byte(REG_SECTOR_COUNT,hd_cmd->sector_count);
- Out_Byte(REG_LBA_LOW,hd_cmd->lba_low);
- Out_Byte(REG_LBA_MID,hd_cmd->lba_mid);
- Out_Byte(REG_LBA_HIGH,hd_cmd->lba_high);
- Out_Byte(REG_DEVICE,hd_cmd->device);
- /*
- 此句执行之后,硬盘驱动器开始工作
- 工作结束后发出一个硬盘中断
- */
- Out_Byte(REG_COMMAND,hd_cmd->command);
- }
其中用到的一些宏定义在hd.h中:
hd.h
- /*
- By Marcus Xing
- include/hd.h
- 与硬盘驱动有关的信息
- */
- /*
- forward include:
- type.h
- */
- #ifndef _HD_H_
- #define _HD_H_
- /* 有关硬盘驱动器的端口号,只考虑挂到IDE0的硬盘 */
- /* 写时 */
- #define REG_DATA 0x1f0
- #define REG_FEATURES 0x1f1
- #define REG_SECTOR_COUNT 0x1f2
- #define REG_LBA_LOW 0x1f3
- #define REG_LBA_MID 0x1f4
- #define REG_LBA_HIGH 0x1f5
- #define REG_DEVICE 0x1f6
- #define REG_COMMAND 0x1f7
- #define REG_DEVICE_CTL 0x3f6
- /* 写时 */
- #define REG_STATUS 0x1f7
- #define CMD_INFO 0xec /* 获得硬盘信息的送给硬盘驱动器寄存器的值 */
- /* 获得device寄存器值的宏 */
- #define MAKE_DEVICE_REG(is_lba,is_master,lba_highest) /
- ((is_lba << 6) | (is_master << 4) | (lba_highest & 0xff) | 0xa0)
- /* 写到硬盘驱动器的各命令寄存器的值的结构 */
- typedef struct s_hd_cmd
- {
- u8 features;
- u8 sector_count;
- u8 lba_low;
- u8 lba_mid;
- u8 lba_high;
- u8 device;
- u8 command;
- }HD_Command;
- #endif
4,要想使硬盘持续响应中断,发生中断程序结束之前不仅要填充EOI到主片,而且还要填充EOI到从片,在kernel/kernel.asm修改:
kernel/kernel.asm
- MASTER equ 0 ;代表8259A主片
- SLAVE equ 1 ;代表8259A从片
- ...
- ;--------------------------------------------------------------HARD_INT_HANDLERS
- ;初始化外中断处理程序的宏
- %macro hw 2
- ;保存寄存器值到当前进程的PCB等功能
- ;调用后下一条指令的地址入PCB的save_ret_addr字段
- call Save
- ;屏蔽当前向量号中断
- push %1
- call Disable_IRQ
- add esp,4
- ;通知8259A此次中断已结束
- mov al,EOI
- mov dx,20h
- out dx,al
- ;判断是否为从主片
- mov eax,%2
- cmp eax,MASTER
- je .1
- nop
- nop
- ;如果为从片还要向级联片发送EOI
- mov al,EOI
- mov dx,0a0h
- out dx,al
- .1:
- sti ;发生中断时CPU自动关中断,这里人为打开
- ;如果是时钟中断
- ;进程调度,中断重入不重入都调度,在函数内判断
- ;跳入相应的处理函数处理
- mov eax,IRQ_Handler_Table
- push %1
- call [eax + (%1 * 4)] ;一个函数指针4字节
- add esp,4
- cli ;准备返回进程前关中断
- ;恢复当前向量号中断
- push %1
- call Enable_IRQ
- add esp,4
- ret ;准备返回
- %endmacro
- ;以下都是宏的扩展
- hw_00:
- hw 0,MASTER ;时钟中断处理程序
- hw_01:
- hw 1,MASTER
- hw_02:
- hw 2,MASTER
- hw_03:
- hw 3,MASTER
- hw_04:
- hw 4,MASTER
- hw_05:
- hw 5,MASTER
- hw_06:
- hw 6,MASTER
- hw_07:
- hw 7,MASTER
- hw_08:
- hw 8,SLAVE
- hw_09:
- hw 9,SLAVE
- hw_10:
- hw 10,SLAVE
- hw_11:
- hw 11,SLAVE
- hw_12:
- hw 12,SLAVE
- hw_13:
- hw 13,SLAVE
- hw_14:
- hw 14,SLAVE
- hw_15:
- hw 15,SLAVE
我们看到,我们的硬盘驱动进程在填充了寄存器后就直接返回了,也没等硬盘中断是否已经执行结束,因为我们先不想获取硬盘中的信息。为了能验证硬盘能否重复响应中断,在FS进程中延迟了3秒以后又发条消息给硬盘驱动进程。
别忘了,我们现在还没硬盘呢,先造一个出来,修改下bochsrc就能用了:
OK,make,bochs: