MacOS环境-手写操作系统-11-建立中断机制

简介: 本文详细介绍了如何为内核建立中断机制,涉及8259A中断控制器的初始化、中断信号的传递过程以及中断描述符表的设置。通过汇编和C语言代码展示了如何处理中断,特别是键盘和鼠标中断,最后给出了编译和运行的步骤。摘要由CSDN通过智能技术生成

建立中断机制

1.简介

上一节,我们绘制了鼠标图案,遗憾的是,鼠标箭头是死的,动不了,要想让鼠标移动,我们需要为内核建立中断机制

当我们移动鼠标时,鼠标会给CPU发送信号,CPU接收到信号后,终止当前的运算,执行内核给定的代码以处理鼠标发送的信号

中断信号的发送机制

每一个8259A控制器有8根中断信号线 总共可以接入15个外设硬件


一般情况下 鼠标接入的是从8259A所对应的IRQ4这根信号线


鼠标发送信号时 先通过管线IRQ4将信号传递到从8259A


然后通过管线IRQ2传递到主8259A


最后信号再传递给CPU 键盘产生的中断通过主8259A的IRQ1管线向CPU发送信号

既然有硬件,那就需要对其初始化后才能使用,对硬件的控制我们前面已经说过,需要通过端口发送命令来完成,要配置这两个控制器,我们需要对指定端口发送1字节的数据,这个一字节(8 bit)的数据,我们称之为ICW(initialization control word).主8259A对应的端口地址是20h,21h, 从8259A对应的端口是A0h和A1h. 对端口发送数据时,顺序是定死的,不能违背:
1. 往端口20h(主片)或A0h(从片)发送ICW1
2. 往端口21h(主片)或A1h(从片)发送ICW2
3. 往端口21h(主片)或A1h(从片)发送ICW3
4. 往端口20h(主片)或A0h(从片)发送ICW4

(这里略过一些概念的东西·· 毕竟比较晦涩难懂 别睡着了)


2.代码控制

下面我们通过代码配置两个中断控制器:


(1)先向主8259A发生ICW1:

mov al, 011h
out 020h, al

011h 对应的二进制是00010001 对应ICW1的说明


由于ICW1[0]=1表示需要发送ICW4, ICW1[1] = 0 说明有级联8259A(我们买来的电脑都是级联的)

ICW1[2] =0 表示用8字节来设置中断向量号


ICW1[3]=0表示中断形式是边沿触发 ICW[4]必须设置为1


ICW[5,6,7]必须是0


(那是相当的晦涩了·· 看个大概就好!后面慢慢懂吧 都是硬件的部分 我不是很关心)


(下面很长一部分都是这些 刚兴趣的可以去看看:https://blog.csdn.net/tyler_download/article/details/52716839


如果你和我一样不敢兴趣 那就先和我一起往下走吧!


综合以上 我们得到了如下的代码:

init8259A:
     mov  al, 011h
     out  02h, al
     call io_delay
  
     out 0A0h, al
     call io_delay

     mov al, 020h
     out 021h, al
     call io_delay

     mov  al, 028h
     out  0A1h, al
     call io_delay

     mov  al, 004h
     out  021h, al
     call io_delay

     mov  al, 002h
     out  0A1h, al
     call io_delay

     mov  al, 003h
     out  021h, al
     call io_delay

     out  0A1h, al
     call io_delay

     mov  al, 11111101b ;允许键盘中断
     out  21h, al
     call io_delay

     mov  al, 11111111b
     out  0A1h, al
     call io_delay

     ret

上边的这段代码 就是汇编部分 调用硬件中断的代码


那二话不说 汇编有了 我们去上C语言:


前面我们处理了硬件如何发送信号的问题


接下来 我们来看看 CPU接收到信号后 如何执行内核指定的代码


要执行相应代码 CPU必须知道代码所在的内存位置 这个信息是通过中断描述符表来实现的


中断描述符的数据结构:


struct GATE_DESCRIPTOR {
  short offset_low;
  short selector;
  char dw_count;
  char attribute;
  short offset_high;
};


中断描述符跟前面说到的全局描述符类似 也是用于描述内存性质的


只不过它专门用于描述可执行代码所在的内存


offset_low 和 offset_high 合在一起作为中断函数在代码执行段中的偏移


selector 用来指向全局描述符表中的某个描述符 中断函数的代码就处于该描述符所指向的段中


dw_count设置为0 attribute设置为08Eh


如何在内核中加载中断描述符表:


;Gate selecotor, offset, DCount, Attr
%macro Gate 4
  dw  (%2 & 0FFFFh)
  dw  %1
  dw  (%3 & 1Fh) | ((%4 << 8) & 0FF00h)
  dw  ((%2>>16) & 0FFFFh)
%endmacro


上面汇编代码中 %2对应的是4字节的地址偏移


把地址偏移的低2字节放到中断门的前两字节


接下来的一字节是宏定义的第一个参数 是中断代码所在的代码段的全局描述符


第三行设置中断描述符的属性 当前写死为08Eh


最后一行设置中断代码偏移的高二字节


在内核代码里 当全局描述符表加载到CPU后 就是我们加载中断描述符表的时机了


首先初始化一个中断描述符:


LABEL_IDT:
%rep  255
    Gate  SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep
IdtLen  equ $ - LABEL_IDT
IdtPtr  dw  IdtLen - 1
        dd  0


上面代码中 通过指令%rep 255 重复定义255个中断描述符


这么说来 CPU其实可以支持255种中断 其中两个8259A芯片的15个中断信号就包含在255个中断中 SpuriousHandler是中断代码的入口 我们把255个中断的处理代码都设置成SpuriousHandler 也就是无论哪个中断发生,都调用这个函数来处理:


 

xor   eax, eax
     mov   ax,  ds
     shl   eax, 4
     add   eax, LABEL_IDT
     mov   dword [IdtPtr + 2], eax
     lidt  [IdtPtr]


上面代码跟以前我们加载全局描述符表是一样的 由于加载全局描述符时我们使用指令cli关闭了中断功能


因此我们需要回复中断功能 CPU才能相应来自8259A芯片的信号:

  [SECTION .s32]
     [BITS  32]
     LABEL_SEG_CODE32:
     ;initialize stack for c code
     mov  ax, SelectorStack
     mov  ss, ax
     mov  esp, TopOfStack

     mov  ax, SelectorVram
     mov  ds,  ax

     mov  ax, SelectorVideo
     mov  gs, ax

     sti
     %include "write_vga_desktop.asm"

     jmp  $

上面的代码通过运行指令sti 恢复中断功能


最后再看看SpuriousHandler的实现


_SpuriousHandler:
SpuriousHandler  equ _SpuriousHandler - $$
call intHandlerFromC
iretd


当点击键盘 引发中断时 _SpuriousHandler的代码被调用 它又调用了C模块实现的函数intHandlerFromC


我们看看C语言怎么实现intHandlerFromC的


void intHandlerFromC(char* esp) {
    char*vram = bootInfo.vgaRam;
    int xsize = bootInfo.screenX, ysize = bootInfo.screenY;
    boxfill8(vram, xsize, COL8_000000, 0,0,32*8 -1, 15);
    showString(vram, xsize, 0, 0, COL8_FFFFFF, "PS/2 keyboard"); 
    for (;;) {
        io_hlt();
    }
    show_char();
}


(虽然晦涩难懂 但是还要看一看的!不可直接略过的!)


3.编译运行

下面又到了编译的时候了···


编译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(直接放大一点)直接读了20个扇区 肯定够用了

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


编译boot

nasm -o boot.bat boot.asm


编译kernel

nasm -o kernel.bat kernel.asm

运行java 生成system.img

目录
相关文章
|
17天前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
21 3
|
17天前
|
存储 资源调度 算法
操作系统的心脏:深入理解内核架构与机制####
【10月更文挑战第16天】 本文旨在揭开操作系统最神秘的面纱——内核,通过剖析其架构设计与关键机制,引领读者一窥究竟。在这篇探索之旅中,我们将深入浅出地讨论内核的基本构成、进程管理的智慧、内存分配的策略,以及那至关重要的系统调用接口,揭示它们是如何协同工作,支撑起现代计算机系统的高效运行。这既是一次技术的深潜,也是对“看不见的手”调控数字世界的深刻理解。 ####
36 3
|
6天前
|
缓存 调度
操作系统的心脏:深入理解内核机制
【10月更文挑战第26天】 在数字化时代,操作系统是计算机系统不可或缺的核心。本文旨在揭示操作系统内核的神秘面纱,探讨其工作原理和重要性。通过深入浅出的语言,我们将一窥究竟,了解内核如何协调硬件与软件,确保计算机系统的稳定运行。
|
1月前
|
存储 C语言 iOS开发
MacOS环境-手写操作系统-48-让内核从错误中恢复
MacOS环境-手写操作系统-48-让内核从错误中恢复
35 0
|
1月前
|
存储 API C语言
MacOS环境-手写操作系统-46,47-C语言开发应用程序
MacOS环境-手写操作系统-46,47-C语言开发应用程序
33 0
|
1月前
|
编译器 API C语言
MacOS环境-手写操作系统-45-C语言开发应用程序
MacOS环境-手写操作系统-45-C语言开发应用程序
42 0
|
1月前
|
小程序 iOS开发 MacOS
MacOS环境-手写操作系统-44-运行简单的程序
MacOS环境-手写操作系统-44-运行简单的程序
19 0
|
3月前
|
关系型数据库 MySQL 数据库
【Mac os系统】安装MySQL数据库
本文详细介绍了在Mac OS系统上安装MySQL数据库的步骤,包括下载、安装、配置环境变量、启动服务、授权设置以及解决常见问题,并提供了一些常用的MySQL命令。
177 0
【Mac os系统】安装MySQL数据库
|
4月前
|
Linux 虚拟化 iOS开发
部署06--MacOS安装VMware Fusion安装
部署06--MacOS安装VMware Fusion安装
|
3月前
|
测试技术 Linux 虚拟化
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
详细的VMware虚拟机安装macOS Big Sur的保姆级教程,包括下载VMware和macOS镜像、图解安装步骤和遇到问题时的解决方案,旨在帮助读者顺利搭建macOS虚拟机环境。
121 3
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS