把class03改成class04

IDT,GDT,PIC

我来介绍什么是IDT和GDT,PIC,怎么实现键盘中断

GDT全局描述表在16位CPU用不到,到了32位CPU要用。

16位CPU实模式用基地址x16+偏移地址去寻找内存地址,到了32位也用基地址x16+偏移地址找地址但是,32位CPU有保护模式,防止程序乱访问内存

所以用GDT

IDT,Interrupt Descriptor Table,即中断描述符表,用来联系中断和处理函数的,比如A中断发生->执行B函数

PIC(可编程中断控制器),中断是由PIC产生的

这是我自己的理解,你要想搞明白得自己去找资料

实现键盘中断

键盘按下-PIC收到发起中断-CPU处理中断-执行对应函数

这是我自己意淫的,具体怎么回事你得自己找资料

首先初始化pic,gdt,idt

创建文件dsctbl.c

  1. /* GDT、IDT、descriptor table 关系处理 */
  2.  
  3. #include "include/head.h"
  4.  
  5. void init_gdtidt(void)
  6. {
  7. struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
  8. struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT;
  9. int i;
  10.  
  11. /* GDT初始化 */
  12. for (i = 0; i <= LIMIT_GDT / 8; i++) {
  13. set_segmdesc(gdt + i, 0, 0, 0);
  14. }
  15. set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW);
  16. set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
  17. load_gdtr(LIMIT_GDT, ADR_GDT);
  18.  
  19. /* IDT初始化 */
  20. for (i = 0; i <= LIMIT_IDT / 8; i++) {
  21. set_gatedesc(idt + i, 0, 0, 0);
  22. }
  23. load_idtr(LIMIT_IDT, ADR_IDT);
  24.  
  25. /* IDT设置*/ set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
  26. /* IDT的设定 */
  27. return;
  28. }
  29.  
  30. void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
  31. {
  32. if (limit > 0xfffff) {
  33. ar |= 0x8000; /* G_bit = 1 */
  34. limit /= 0x1000;
  35. }
  36. sd->limit_low = limit & 0xffff;
  37. sd->base_low = base & 0xffff;
  38. sd->base_mid = (base >> 16) & 0xff;
  39. sd->access_right = ar & 0xff;
  40. sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
  41. sd->base_high = (base >> 24) & 0xff;
  42. return;
  43. }
  44.  
  45. void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
  46. {
  47. gd->offset_low = offset & 0xffff;
  48. gd->selector = selector;
  49. gd->dw_count = (ar >> 8) & 0xff;
  50. gd->access_right = ar & 0xff;
  51. gd->offset_high = (offset >> 16) & 0xffff;
  52. return;
  53. }

加粗的地方就是注册21号键盘中断处理函数到IDT

head.h

  1. /*naskfunc.asm*/
  2. void io_stihlt();
  3. void io_hlt(void);
  4. void io_cli(void);
  5. void io_sti(void);
  6. int io_get8(int port);
  7. void io_set8(int port, int data);
  8. void write_mem8(int addr, int data);
  9. int io_load_eflags(void);
  10. void io_store_eflags(int eflags);
 void load_gdtr(int limit, int addr);
 void load_idtr(int limit, int addr);
  1. void asm_inthandler21(void);
  2. /* asmhead.nas */
  3. struct BOOTINFO { /* 0x0ff0-0x0fff */
  4. char cyls; /* 启动区读磁盘读到此为止 */
  5. char leds; /* 启动时键盘的LED的状态 */
  6. char vmode; /* 显卡模式为多少位彩色 */
  7. char reserve;
  8. short scrnx, scrny; /* 画面分辨率 */
  9. char *vram;
  10. };
  11. #define ADR_BOOTINFO 0x00000ff0
  12.  
  13. /*graphic.c*/
  14. void init_palette(void);
  15. void set_palette(int start, int end, unsigned char *rgb);
  16. void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
  17. void putfont8(char *vram, int xsize, int x, int y, char c, char *font);
  18. void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s);
  19.  
  20. /*font*/
  21. extern char font[4096];
  22.  
  23. /* dsctbl.c */
  24. struct SEGMENT_DESCRIPTOR {
  25. short limit_low, base_low;
  26. char base_mid, access_right;
  27. char limit_high, base_high;
  28. };
  29. struct GATE_DESCRIPTOR {
  30. short offset_low, selector;
  31. char dw_count, access_right;
  32. short offset_high;
  33. };
  34. void init_gdtidt(void);
  35. void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);
  36. void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);
  37. #define ADR_IDT 0x0026f800
  38. #define LIMIT_IDT 0x000007ff
  39. #define ADR_GDT 0x00270000
  40. #define LIMIT_GDT 0x0000ffff
  41. #define ADR_BOTPAK 0x00280000
  42. #define LIMIT_BOTPAK 0x0007ffff
  43. #define AR_DATA32_RW 0x4092
  44. #define AR_CODE32_ER 0x409a
  45. #define AR_INTGATE32 0x008e
  46. /* pic.c */
  47. void init_pic(void);
  48. #define PIC0_ICW1 0x0020
  49. #define PIC0_OCW2 0x0020
  50. #define PIC0_IMR 0x0021
  51. #define PIC0_ICW2 0x0021
  52. #define PIC0_ICW3 0x0021
  53. #define PIC0_ICW4 0x0021
  54. #define PIC1_ICW1 0x00a0
  55. #define PIC1_OCW2 0x00a0
  56. #define PIC1_IMR 0x00a1
  57. #define PIC1_ICW2 0x00a1
  58. #define PIC1_ICW3 0x00a1
  59. #define PIC1_ICW4 0x00a1

/*interrupt.c*/
void inthandler21(int *esp);
  1.  

加粗的地方就是增加的地方

naskfunc.asm

  1. ; naskfunc
  2. ; TAB=4
  3.  
  4. [FORMAT "WCOFF"] ; 制作目标文件的模式
  5. [INSTRSET "i486p"] ; 使用到486为止的指令
  6. [BITS 32] ; 3制作32位模式用的机器语言
  7. [FILE "naskfunc.asm"] ; 文件名
  8. GLOBAL _io_hlt,_write_mem8,_io_cli,_io_sti,_io_get8,_io_set8,_io_stihlt
  9. GLOBAL _io_load_eflags,_io_store_eflags,_asm_inthandler21
  10. GLOBAL _load_gdtr, _load_idtr
  11. EXTERN _inthandler21
  12.  
  13. [SECTION .text]
  14.  
  15. _io_hlt: ; void io_hlt(void);
  16. HLT
  17. RET
  18.  
  19. _io_cli: ; void io_cli(void);
  20. CLI
  21. RET
  22.  
  23. _io_sti: ; void io_sti(void);
  24. STI
  25. RET
  26.  
  27. _io_get8: ; int io_get8(int port);
  28. MOV EDX,[ESP+4] ; port
  29. MOV EAX,0
  30. IN AL,DX
  31. RET
  32.  
  33. _io_set8: ; void io_set8(int port, int data);
  34. MOV EDX,[ESP+4] ; port
  35. MOV AL,[ESP+8] ; data
  36. OUT DX,AL
  37. RET
  38.  
  39. _io_stihlt: ; void io_stihlt(void);
  40. STI
  41. HLT
  42. RET
  43.  
  44. _write_mem8: ; void write_mem8(int addr, int data);
  45. MOV ECX,[ESP+4] ; taking content of add
  46. MOV AL,[ESP+8] ; taking content of data
  47. MOV [ECX],AL ; *ecx=al
  48. RET
  49. _io_load_eflags: ; int io_load_eflags(void);
  50. PUSHFD ; PUSH EFLAGS
  51. POP EAX
  52. RET
  53.  
  54. _io_store_eflags: ; void io_store_eflags(int eflags);
  55. MOV EAX,[ESP+4]
  56. PUSH EAX
  57. POPFD ; POP EFLAGS
  58. RET
  59. _load_gdtr: ; void load_gdtr(int limit, int addr);
  60. MOV AX,[ESP+4] ; limit
  61. MOV [ESP+6],AX
  62. LGDT [ESP+6]
  63. RET
  64. _load_idtr: ; void load_idtr(int limit, int addr);
  65. MOV AX,[ESP+4] ; limit
  66. MOV [ESP+6],AX
  67. LIDT [ESP+6]
  68. RET
  69. _asm_inthandler21:
  70. PUSH ES
  71. PUSH DS
  72. PUSHAD
  73. MOV EAX,ESP
  74. PUSH EAX
  75. MOV AX,SS
  76. MOV DS,AX
  77. MOV ES,AX
  78. CALL _inthandler21
  79. POP EAX
  80. POPAD
  81. POP DS
  82. POP ES
  83. IRETD

加粗的地方就是要修改的地方

IDT-->_asm_inthandler21-->_inthandler21函数

新建pic.c

  1. /*初始化关系 */
  2.  
  3. #include "include/head.h"
  4.  
  5. void init_pic(void)
  6. /* PIC初始化 */
  7. {
  8. io_set8(PIC0_IMR, 0xff ); /* 禁止所有中断 */
  9. io_set8(PIC1_IMR, 0xff ); /* 禁止所有中断 */
  10.  
  11. io_set8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */
  12. io_set8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */
  13. io_set8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */
  14. io_set8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */
  15.  
  16. io_set8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */
  17. io_set8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */
  18. io_set8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */
  19. io_set8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */
  20.  
  21. io_set8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */
  22. io_set8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */
  23.  
  24. return;
  25. }

创建interrupt.c

  1. #include "include/head.h"
  2.  
  3. void inthandler21(int *esp)
  4. /* 来自PS/2键盘的中断 */
  5. {
  6. struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
  7. boxfill8(binfo->vram, binfo->scrnx, 7, 0, 0, 32 * 8 - 1, 15);
  8. putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, 0, "INT 21 (IRQ-1) :PS/2 keyboard");
  9. for (;;) {
  10. io_hlt();
  11. }
  12. }

最后修改mian.c

  1. #include "include/head.h"
  2. #include <string.h>
  3.  
  4. struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
  5.  
  6. void Main(void){
  7. int i;char s[256];
  8.  
  9. init_gdtidt();
  10. init_pic();
  11. io_sti();
  12.  
  13. init_palette();
  14.  
  15. boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny);
  16. sprintf(s, "scrnx = %d", binfo->scrnx);
  17. putfonts8_asc(binfo->vram, binfo->scrnx, 8, 8, 7, s);
  18. io_set8(PIC0_IMR, 0xf9); /* 开放PIC1和键盘中断(11111001) */

  19. for (;;) {
  20. io_hlt();
  21. }
  22. }

别忘了编译之改一下makefile

 运行:

  1. cd class02
  2. ..\z_tools\make.exe run
 
自制操作系统合集
原文地址:https://www.cnblogs.com/Frank-dev-blog/category/2249116.html
项目github地址rick521/My-OS (github.com)给我点颗star

0x06_自制操作系统My-OS,IDT,GDT,PIC初始化,实现键盘中断的更多相关文章

  1. [自制简单操作系统] 2、鼠标及键盘中断处理事件[PIC\GDT\IDT\FIFO]

    1.大致介绍: >_<" 大致执行顺序是:ipl10.nas->asmhead.nas->bootpack.c PS: 这里bootpack.c要调用graphic. ...

  2. 《30天自制操作系统》读书笔记(5) GDT&IDT

    梳理项目结构 项目做到现在, 前头的好多东西都忘了, 还是通过Makefile重新理解一下整个项目是如何编译的: 现在我们拥有这么9个文件: ipl10.nas    InitialProgramLo ...

  3. 《30天自制操作系统》笔记(01)——hello bitzhuwei’s OS!

    <30天自制操作系统>笔记(01)——hello bitzhuwei's OS! 最初的OS代码 ; hello-os ; TAB=4 ORG 0x7c00 ; 指明程序的装载地址 ; 以 ...

  4. 《30天自制操作系统》笔记(01)——hello bitzhuwei’s OS!【转】

    转自:http://www.cnblogs.com/bitzhuwei/p/OS-in-30-days-01-hello-bitzhuwei-OS.html 阅读目录(Content) 最初的OS代码 ...

  5. 《30天自制操作系统》笔记(06)——CPU的32位模式

    <30天自制操作系统>笔记(06)——CPU的32位模式 进度回顾 上一篇中实现了启用鼠标.键盘的功能.屏幕上会显示出用户按键.点击鼠标的情况.这是通过设置硬件的中断函数实现的,可以说硬件 ...

  6. 《30天自制操作系统》笔记(02)——导入C语言

    <30天自制操作系统>笔记(02)——导入C语言 进度回顾 在上一篇,记录了计算机开机时加载IPL程序(initial program loader,一个nas汇编程序)的情况,包括IPL ...

  7. 自制操作系统 (三) 从启动区执行操作系统并进入C世界

    qq:992591601 欢迎交流 2016.04.03 2016.05.31 2016.06.29 这一章是有些复杂的,我不太懂作者为什么要把这么多内容都放进一天. 1读入了十个柱面 2从启动区执行 ...

  8. 《30天自制操作系统》12_day_学习笔记

    harib09a: 定时器:(Timer)每隔一段时间,会向CPU发送一个中断.这样CPU不用记住每一条指令的执行时间.没有定时器很多指令CPU都很难执行.例如HLT指令,这个指令的执行时间不是个固定 ...

  9. 《30天自制操作系统》笔记(03)——使用Vmware

    <30天自制操作系统>笔记(03)——使用Vmware 进度回顾 在上一篇,实现了用IPL加载OS程序到内存,然后JMP到OS程序这一功能:并且总结出下一步的OS开发结构.但是遇到了真机测 ...

  10. 《30天自制操作系统》06_day_学习笔记

    harib03a: 内容没有变化 :P109 从这里开始,代码开始工程化了. 将原本300多行的bootpack.c分割成了三部分: graphic.c      : 用来处理界面图像 dsctbl. ...

随机推荐

  1. 大前端系统学-了解html

    标签: 使用尖括号包起来的就是标签,例如我们看到的  <html></html> 一对标签 <head>  开始标签 </head> 结束标签 < ...

  2. vuex环境配置及使用

    vuex环境搭建 1.下载vuex,如果你是开发Vue2,请下载vuex3版本 npm i vuex@3 2.搭建vuex的环境配置 ​ 创建 src/state/index.js 文件 //导入Vu ...

  3. uni 结合vuex 编写动态全局配置变量 this.baseurl

    在日常开发过程,相信大家有遇到过各种需求,而我,在这段事件便遇到了一个,需要通过用户界面配置动态接口,同时,因为是app小程序开发,所以接口中涉及到了http以及websocket两个类型的接口. 同 ...

  4. K8s架构|全面整理K8s的架构介绍

    K8S架构与核心技术介绍 1. 架构图 1.1 整体结构图 1.2 组件间的协议 CNI: CNI是Container Network Interface的是一个标准的,通用的接口 ;用于连接容器管理 ...

  5. 【云原生 • Docker】mysql、tomcat、nginx、redis 环境部署

    注意在应用部署之前,docker 服务必须是开启状态 systemctl start docker. 目录 一.MySQL 部署 二.Tomcat 部署 三.Nginx 部署 四.Redis 部署 一 ...

  6. Java工厂模式的最佳实践?

    "Simplicity is prerequisite for reliability." - Edsger Dijkstra "简单是可靠的前提条件." -- ...

  7. React报错之Function components cannot have string refs

    总览 当我们在一个函数组件中使用一个字符串作为ref时,会产生"Function components cannot have string refs"错误.为了解决该错误,使用u ...

  8. 大角度非迭代的空间坐标旋转C#实现

    1. 绪论 在前面文章中提到空间直角坐标系相互转换,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换.这个就是我们经常在测绘数据处理中,WGS-84坐标系.54北京坐标系.80西安坐标系 ...

  9. 命令指定IP端口号

    tcping命令是针对tcp监控的,也可以看到ping值,即使源地址禁ping也可以通过tcping来监控服务器网络状态,除了简单的ping之外,tcping最大的一个特点就是可以指定端口. 将下载好 ...

  10. loadrunner11安装时提示缺少Microsoft Visual c++2005 sp1组件的解决办法

    解决方法: 1.进入loadrunner-11安装程序\loadrunner-11\Additional Components\IDE Add-Ins\MS Visual Studio .NET文件夹 ...