MacOS环境-手写操作系统-13-鼠标中断

简介: MacOS环境-手写操作系统-13-鼠标中断

鼠标内核的中断处理

1.简介

如果大家还记得描述8259A中断控制器那一小节的话


鼠标发送中断信号的数据线在从8259A芯片的IRQ4信号线


因此 为了接收鼠标中断信号 我们在初始化中断控制芯片时 必须启用该信号线


同时 从8259A芯片是通过主8259A的IRQ2信号线连接在一起的


所以也必须同时启动主8259A芯片的IRQ2信号线


这样 我们在内核中要对init8259A代码段做一些改动


init8259A:
...
mov  al, 11111001b ;允许键盘中断
out  021h, al
call io_delay
mov  al, 11101111b ;允许鼠标中断
out  0A1h, al
call io_delay
ret

mov al, 11111001b 这一句指令 启用了主8259A芯片的IRQ1和IRQ2两根信号线


mov al, 11101111b 这句指令启用了从8259A的IRQ4信号线 这根信号线就是用来发送鼠标信号的


只要是外接硬件 要想使用 就得对其进行配置和初始化


硬件的初始化 一般就是对给定端口发送几个数据而已 鼠标自然也不例外


2.代码

鼠标电路的初始化


鼠标电路对应的一个端口是 0x64


通过读取这个端口的数据来检测鼠标电路的状态 内核会从这个端口读入一个字节的数据


如果该字节的第二个比特位为0 那表明鼠标电路可以接受来自内核的命令


因此 在给鼠标电路发送数据前 内核需要反复从0x64端口读取数据 并检测读到数据的第二个比特位 知道该比特位为0时 才着手发送控制信息


代码如下:


#define  PORT_KEYDAT  0x0060
#define  PORT_KEYSTA  0x0064
#define  PORT_KEYCMD  0x0064
#define  KEYSTA_SEND_NOTREADY  0x02
#define  KEYCMD_WRITE_MODE  0x60
#define  KBC_MODE     0x47
void  wait_KBC_sendready() {
    for(;;) {
        if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
            break;
        }
    }
}

for循环一直从端口读取数据 然后检测比特位 只有对应比特位是0时 才返回


大家看到 上面代码中 居然有一个端口是 0x60


你可能会困惑 0x60不是键盘电路的端口吗?


没错 鼠标的初始化 就是得通过键盘电路来实现的


当对应比特位为0 也就是鼠标可以接收数据了


这时候 我们就得通过向端口0x60发送数据来配置鼠标


void init_keyboard(void) {
    wait_KBC_sendready();
    io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
    wait_KBC_sendready();
    io_out8(PORT_KEYDAT, KBC_MODE);
    return;
}


上面代码中 先等待0x64端口返回可写信号


然后继续向端口发送一个字节数据 这个字节数值是 0x60 该数据让键盘电路进入数据接收状态


紧接着向端口0x60发送一个字节的数据0x47 这个数据要求键盘电路启动鼠标模式


这样 鼠标硬件所产生的数据信息 都可以通过键盘电路端口0x60读到


至于为什么鼠标会跟键盘电路勾搭在一起 我也不清楚 也不知道当时IBM的设计人员是怎么想的(哈哈)


当我们想向鼠标发送数据时


先向端口发送一个字节的数据 改数据的值是0xd4


完成这一步后 任何向端口0x60写入的数据都会被传送给鼠标:


#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
void enable_mouse(void) {
    wait_KBC_sendready();
    io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
    wait_KBC_sendready();
    io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
    return;
}


io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE)


这一句就是向端口0x64写入一个字节的数据 即0xd4


然后o_out8(PORT_KEYDAT, MOUSECMD_ENABLE)


这一句是向端口0x60写入一字节数据 该数据的数值为0xf4


这个数据会被键盘电路发送给鼠标 该数据的作用是对鼠标进行激活 鼠标一旦接收到该数据后 立马向CPU发送中断信号


如果这时候 我们设置好鼠标的中断处理函数的话 相关函数的代码就会被CPU执行


我们先看看如何设置鼠标的中断函数


LABEL_IDT:
%rep  33
    Gate  SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep
.021h:
    Gate SelectorCode32, KeyBoardHandler,0, DA_386IGate
%rep  10
    Gate  SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep
.2CH:
    Gate SelectorCode32, mouseHandler,0, DA_386IGate


我们在初始化8259A芯片时 将主8259A的初始中断向量设置为0x20,把从8259A的初始中断向量设置为0x28


由于鼠标中断信号线是从8259A的IRQ4


所以鼠标的中断向量就是0x28 + 4 = 0x2C


从上面代码看来 鼠标的中断处理函数叫mouseHandler


我们看看它的代码:

_mouseHandler:
mouseHandler equ _mouseHandler - $$
     push es
     push ds
     pushad
     mov  eax, esp
     push eax

     call intHandlerForMouse


     pop  eax
     mov  esp, eax
     popad
     pop  ds
     pop  es
     iretd

我们又调用了来自C语言实现的函数叫intHandlerForMouse


我们再看看其实现:


void intHandlerForMouse(char* esp) {
    char*vram = bootInfo.vgaRam;
    int xsize = bootInfo.screenX, ysize = bootInfo.screenY;
    showString(vram, xsize, 0, 0, COL8_FFFFFF, "PS/2 Mouse Handler");   
    for(;;) {
        io_hlt();
    }
}


3.编译运行

编译C文件


i386-elf-gcc -m32 -fno-asynchronous-unwind-tables -s -c -o write_vga_desktop_mouse_init.o write_vga_desktop_mouse_init.c


反汇编o文件


./objconv -fnasm write_vga_desktop_mouse_init.o write_vga_desktop_mouse_init.asm


删除无用部分


修改kernel


%include "write_vga_desktop_mouse_init.asm"


修改boot(直接放大一点)直接读了18个扇区 肯定够用了


mov          AL,  18        ; AL 表示要练习读取几个扇区


编译boot


nasm -o boot.bat boot.asm


编译kernel


nasm -o kernel.bat kernel.asm


运行java 生成system.img

4.缓存机制的改进

鼠标激活后 只要鼠标稍微有点移动 它都会向CPU发送大量的坐标数据


因此内核要能够把鼠标发送的数据合适的存储起来 以便中断函数进行相应的处理


我们上面提供的缓存机制不够灵活 因为缓存空间只限定在32字节 这对鼠标来说是不够用的


这里我们对原有机制进行改进,以便用于处理鼠标发送的信息:

struct FIFO8 {
    unsigned char* buf;
    int p, q, size, free, flags;
};

void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf) {
    fifo->size = size;
    fifo->buf = buf;
    fifo->free = size;
    fifo->flags = 0;
    fifo->p = 0;
    fifo->q = 0;
    return ;
}

#define FLAGS_OVERRUN 0x0001
int fifo8_put(struct FIFO8 *fifo, unsigned char data) {
    if (fifo->free ==0) {
        fifo->flags |= FLAGS_OVERRUN;
        return -1;
    }

    fifo->buf[fifo->p] = data;
    fifo->p++;
    if (fifo->p == fifo->size) {
        fifo->p = 0;
    }

    fifo->free--;
    return 0;
}

int fifo8_get(struct FIFO8 *fifo) {
    int data;
    if (fifo->free == fifo->size) {
        return -1;
    }

    data = fifo->buf[fifo->q];
    fifo->q++;
    if (fifo->q == fifo->size) {
        fifo->q = 0;
    }

    fifo->free++;
    return data;
}

int fifo8_status(struct FIFO8 *fifo) {
    return fifo->size - fifo->free;
}

FIFO8 是用于数据缓存的结构体 里面的buf可以根据不同的需求进行变换


如果用于键盘缓冲 可以通过fifo8_init设置32字节的内存


如果用于键盘缓存 也可以通过fifo8_init设置128字节的缓存用于鼠标


修改后代码为:


write_vga_desktop_fifo.c (这里我就不编译运行了)


5.从鼠标接受数据

在原有的鼠标中断处理函数中做如下改进:

static struct FIFO8 keyinfo;
static struct  FIFO8 mouseinfo;

static char keybuf[32];
static char  mousebuf[128];

void CMain(void) {
    ....
    fifo8_init(&mouseinfo, 128, mousebuf);
    ....

    int data = 0;
    for(;;) {
       io_cli();
       if (fifo8_status(&keyinfo) + fifo8_status(&mouseinfo)  == 0) {
           io_stihlt();
       } else if(fifo8_status(&keyinfo) != 0){
           io_sti();
           data = fifo8_get(&keyinfo);
           char* pStr = charToHexStr(data);
           static int showPos = 0;
           showString(vram, xsize, showPos, 0, COL8_FFFFFF, pStr);
           showPos += 32; 

       } else if (fifo8_status(&mouseinfo) != 0) {
           show_mouse_info();
       }
    }
}

void  show_mouse_info() {
    char*vram = bootInfo.vgaRam;
    int xsize = bootInfo.screenX, ysize = bootInfo.screenY;
    unsigned char data = 0;

    io_sti();
    data = fifo8_get(&mouseinfo);
    char* pStr = charToHexStr(data);
    static int mousePos = 16;
    if (mousePos <= 256) {
        showString(vram, xsize, mousePos, 16, COL8_FFFFFF, pStr);
        mousePos += 32;
    }
}

void intHandlerForMouse(char* esp) {
    unsigned char data;
    io_out8(PIC1_OCW2, 0x20);
    io_out8(PIC_OCW2, 0x20);

    data = io_in8(PORT_KEYDAT);
    fifo8_put(&mouseinfo, data);
}

在入口函数CMain 中 先初始化鼠标的缓存结构体


在intHandlerForMouse中 PIC1_OCW2 的值是0xA0 也就是从8259A芯片的端口


PIC_OCW2是主8259A芯片的端口 每当中断处理后 要想再次接收中断信号 就必须向中断控制器发送一个字节的数据


这个字节数据叫OCW2 它值得我们详细了解下:

OCW2[0-2] 用来表示中断的优先级


OCW2[3-4]这两位必须设置为0


OCW[5]这一位称之为End of Interrupt


这一位设置为1 表示当前中断处理结束 控制器可以继续调用中断函数处理到来的中断信号 要想下一次继续处理中断信号 这一位必须设置为1


OCW2[6-7]这两位我们不用关心 设置为0即可 我们代码中发送OCW2时的数值是0x20 也就是仅仅把OCW[5]设置为1即可


接着把鼠标发送的数据从端口0x60读取 并通过fifo8_put写入到鼠标缓冲区中


在CMain中,通过


if (fifo8_status(&keyinfo) + fifo8_status(&mouseinfo) == 0)


判断键盘或鼠标缓冲区是否有数据到达


如果有 上面的if判断就会成立 成立后 要进一步判断是数据在键盘缓冲区还是鼠标缓冲区


如果是在鼠标缓冲区 则调用show_mouse_info将数据显示到桌面上


6.最终编译运行

编译C文件


i386-elf-gcc -m32 -fno-asynchronous-unwind-tables -s -c -o write_vga_desktop.o write_vga_desktop.c


反汇编o文件


./objconv -fnasm write_vga_desktop.o write_vga_desktop.asm


删除无用部分


修改kernel


%include "write_vga_desktop.asm"


修改boot(直接放大一点)直接读了18个扇区 肯定够用了


mov          AL,  18        ; AL 表示要练习读取几个扇区


编译boot


nasm -o boot.bat boot.asm


编译kernel


nasm -o kernel.bat kernel.asm


运行java 生成system.img

目录
相关文章
|
2月前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
48 3
|
2月前
|
存储 C语言 iOS开发
MacOS环境-手写操作系统-48-让内核从错误中恢复
MacOS环境-手写操作系统-48-让内核从错误中恢复
39 0
|
2月前
|
存储 API C语言
MacOS环境-手写操作系统-46,47-C语言开发应用程序
MacOS环境-手写操作系统-46,47-C语言开发应用程序
35 0
|
2月前
|
编译器 API C语言
MacOS环境-手写操作系统-45-C语言开发应用程序
MacOS环境-手写操作系统-45-C语言开发应用程序
49 0
|
2月前
|
小程序 iOS开发 MacOS
MacOS环境-手写操作系统-44-运行简单的程序
MacOS环境-手写操作系统-44-运行简单的程序
23 0
|
4月前
|
关系型数据库 MySQL 数据库
【Mac os系统】安装MySQL数据库
本文详细介绍了在Mac OS系统上安装MySQL数据库的步骤,包括下载、安装、配置环境变量、启动服务、授权设置以及解决常见问题,并提供了一些常用的MySQL命令。
248 0
【Mac os系统】安装MySQL数据库
|
5月前
|
Linux 虚拟化 iOS开发
部署06--MacOS安装VMware Fusion安装
部署06--MacOS安装VMware Fusion安装
|
4月前
|
测试技术 Linux 虚拟化
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
详细的VMware虚拟机安装macOS Big Sur的保姆级教程,包括下载VMware和macOS镜像、图解安装步骤和遇到问题时的解决方案,旨在帮助读者顺利搭建macOS虚拟机环境。
166 3
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
|
4月前
|
虚拟化 数据安全/隐私保护 iOS开发
VMware——安装MacOS 系统教程(仅供学习交流)
VMware——安装MacOS 系统教程(仅供学习交流)
86 4
|
6月前
|
Java Shell 开发工具
03. 【Java教程】在 MacOS 上安装 Java
03. 【Java教程】在 MacOS 上安装 Java
62 1