把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

/* GDT、IDT、descriptor table 关系处理 */

#include "include/head.h"

void init_gdtidt(void)
{
struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT;
int i; /* GDT初始化 */
for (i = 0; i <= LIMIT_GDT / 8; i++) {
set_segmdesc(gdt + i, 0, 0, 0);
}
set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW);
set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
load_gdtr(LIMIT_GDT, ADR_GDT); /* IDT初始化 */
for (i = 0; i <= LIMIT_IDT / 8; i++) {
set_gatedesc(idt + i, 0, 0, 0);
}
load_idtr(LIMIT_IDT, ADR_IDT); /* IDT设置*/ set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
/* IDT的设定 */
return;
} void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
if (limit > 0xfffff) {
ar |= 0x8000; /* G_bit = 1 */
limit /= 0x1000;
}
sd->limit_low = limit & 0xffff;
sd->base_low = base & 0xffff;
sd->base_mid = (base >> 16) & 0xff;
sd->access_right = ar & 0xff;
sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
sd->base_high = (base >> 24) & 0xff;
return;
} void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
{
gd->offset_low = offset & 0xffff;
gd->selector = selector;
gd->dw_count = (ar >> 8) & 0xff;
gd->access_right = ar & 0xff;
gd->offset_high = (offset >> 16) & 0xffff;
return;
}

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

head.h

/*naskfunc.asm*/
void io_stihlt();
void io_hlt(void);
void io_cli(void);
void io_sti(void);
int io_get8(int port);
void io_set8(int port, int data);
void write_mem8(int addr, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);
 void load_gdtr(int limit, int addr);
 void load_idtr(int limit, int addr);
void asm_inthandler21(void);

/* asmhead.nas */
struct BOOTINFO { /* 0x0ff0-0x0fff */
char cyls; /* 启动区读磁盘读到此为止 */
char leds; /* 启动时键盘的LED的状态 */
char vmode; /* 显卡模式为多少位彩色 */
char reserve;
short scrnx, scrny; /* 画面分辨率 */
char *vram;
};
#define ADR_BOOTINFO 0x00000ff0 /*graphic.c*/
void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void putfont8(char *vram, int xsize, int x, int y, char c, char *font);
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); /*font*/
extern char font[4096]; /* dsctbl.c */
struct SEGMENT_DESCRIPTOR {
short limit_low, base_low;
char base_mid, access_right;
char limit_high, base_high;
};
struct GATE_DESCRIPTOR {
short offset_low, selector;
char dw_count, access_right;
short offset_high;
};
void init_gdtidt(void);
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);
#define ADR_IDT 0x0026f800
#define LIMIT_IDT 0x000007ff
#define ADR_GDT 0x00270000
#define LIMIT_GDT 0x0000ffff
#define ADR_BOTPAK 0x00280000
#define LIMIT_BOTPAK 0x0007ffff
#define AR_DATA32_RW 0x4092
#define AR_CODE32_ER 0x409a
#define AR_INTGATE32 0x008e /* pic.c */
void init_pic(void);
#define PIC0_ICW1 0x0020
#define PIC0_OCW2 0x0020
#define PIC0_IMR 0x0021
#define PIC0_ICW2 0x0021
#define PIC0_ICW3 0x0021
#define PIC0_ICW4 0x0021
#define PIC1_ICW1 0x00a0
#define PIC1_OCW2 0x00a0
#define PIC1_IMR 0x00a1
#define PIC1_ICW2 0x00a1
#define PIC1_ICW3 0x00a1
#define PIC1_ICW4 0x00a1

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

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

naskfunc.asm

; naskfunc
; TAB=4 [FORMAT "WCOFF"] ; 制作目标文件的模式
[INSTRSET "i486p"] ; 使用到486为止的指令
[BITS 32] ; 3制作32位模式用的机器语言
[FILE "naskfunc.asm"] ; 文件名
GLOBAL _io_hlt,_write_mem8,_io_cli,_io_sti,_io_get8,_io_set8,_io_stihlt
GLOBAL _io_load_eflags,_io_store_eflags,_asm_inthandler21
GLOBAL _load_gdtr, _load_idtr
EXTERN _inthandler21
[SECTION .text] _io_hlt: ; void io_hlt(void);
HLT
RET _io_cli: ; void io_cli(void);
CLI
RET _io_sti: ; void io_sti(void);
STI
RET _io_get8: ; int io_get8(int port);
MOV EDX,[ESP+4] ; port
MOV EAX,0
IN AL,DX
RET _io_set8: ; void io_set8(int port, int data);
MOV EDX,[ESP+4] ; port
MOV AL,[ESP+8] ; data
OUT DX,AL
RET _io_stihlt: ; void io_stihlt(void);
STI
HLT
RET _write_mem8: ; void write_mem8(int addr, int data);
MOV ECX,[ESP+4] ; taking content of add
MOV AL,[ESP+8] ; taking content of data
MOV [ECX],AL ; *ecx=al
RET
_io_load_eflags: ; int io_load_eflags(void);
PUSHFD ; PUSH EFLAGS
POP EAX
RET _io_store_eflags: ; void io_store_eflags(int eflags);
MOV EAX,[ESP+4]
PUSH EAX
POPFD ; POP EFLAGS
RET
_load_gdtr: ; void load_gdtr(int limit, int addr);
MOV AX,[ESP+4] ; limit
MOV [ESP+6],AX
LGDT [ESP+6]
RET _load_idtr: ; void load_idtr(int limit, int addr);
MOV AX,[ESP+4] ; limit
MOV [ESP+6],AX
LIDT [ESP+6]
RET
_asm_inthandler21:
PUSH ES
PUSH DS
PUSHAD
MOV EAX,ESP
PUSH EAX
MOV AX,SS
MOV DS,AX
MOV ES,AX
CALL _inthandler21
POP EAX
POPAD
POP DS
POP ES
IRETD

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

IDT-->_asm_inthandler21-->_inthandler21函数

新建pic.c

/*初始化关系 */

#include "include/head.h"

void init_pic(void)
/* PIC初始化 */
{
io_set8(PIC0_IMR, 0xff ); /* 禁止所有中断 */
io_set8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ io_set8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */
io_set8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */
io_set8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */
io_set8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ io_set8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */
io_set8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */
io_set8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */
io_set8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ io_set8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */
io_set8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ return;
}

创建interrupt.c

#include "include/head.h"

void inthandler21(int *esp)
/* 来自PS/2键盘的中断 */
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
boxfill8(binfo->vram, binfo->scrnx, 7, 0, 0, 32 * 8 - 1, 15);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, 0, "INT 21 (IRQ-1) :PS/2 keyboard");
for (;;) {
io_hlt();
}
}

最后修改mian.c

#include "include/head.h"
#include <string.h> struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; void Main(void){
int i;char s[256]; init_gdtidt();
init_pic();
io_sti();
init_palette(); boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny);
sprintf(s, "scrnx = %d", binfo->scrnx);
putfonts8_asc(binfo->vram, binfo->scrnx, 8, 8, 7, s);
io_set8(PIC0_IMR, 0xf9); /* 开放PIC1和键盘中断(11111001) */

for (;;) {
io_hlt();
}
}

别忘了编译之改一下makefile

 运行:

cd class02
..\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. C温故补缺(七):函数指针与回调函数

    函数指针与回调函数 函数指针就是指向函数调用栈地址的指针,定义时须和函数的返回值类型,参数类型相同 如: #include<stdio.h> int max(int x,int y){ r ...

  2. js 获取相同name元素的属性值

    如图有8-12月5个文本域,id为plan8-12,name同为plan. 现在要获取name同为plan的所有属性值: 方法一: var allplan =document.getElementsB ...

  3. 14 STL-常用算法

    ​ 重新系统学习c++语言,并将学习过程中的知识在这里抄录.总结.沉淀.同时希望对刷到的朋友有所帮助,一起加油哦! 每一次学习都是为了追求智慧! 写在前面,本篇章主要介绍STL中常用算法. 算法主要由 ...

  4. CBV如何添加装饰器?

    目录 一:CBV如何添加装饰器 1.CBV中django不建议直接给类的方法加装饰器 2.CBC添加装饰器的三种方法 3.CBV添加装饰器实战 一:CBV如何添加装饰器 1.CBV中django不建议 ...

  5. 如何查看计算机的CPU信息

    CPU-Z是一款家喻户晓的CPU检测软件,是检测CPU使用程度极高的一款软件.它支持的CPU种类相当全面,软件的启动速度及检测速度都很快.另外,它还能检测主板和内存的相关信息,其中就有我们常用的内存双 ...

  6. java中的自增运算

    本文主要阐明java中的自增运算 1.当i ++ 与 ++ i作为单独语句时,作用与i = i +1一样 2.当赋值时,结果就不一样了 temp = i ++: 操作顺序:1)temp = i: 2) ...

  7. Flask初步认识

    1.Flask基本认识 Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展包(数据库Flask-SQLAlchemy),都需要用第三方的扩展来实现.比如可以用 Flask 扩展加入ORM. ...

  8. 网络监测工具之Zabbix的搭建与测试方法(一)

    简介 Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案,它能监视各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位/解决存在的 ...

  9. 使用jquery—Canvas实现html5小游戏——《坦克大战》

    目录 1.项目背景 2.项目展示 3.设计思路 3.1.坦克移动 3.2.坦克开火 3.3.击中坦克 4.实现代码 5.总结 1.项目背景 2021年春节期间在家无聊,正好又学过一些前端的知识,因此就 ...

  10. 痞子衡嵌入式:MCUBootUtility v4.0发布,开始支持MCX啦

    -- 痞子衡维护的 NXP-MCUBootUtility 工具距离上一个大版本(v3.5.0)发布过去 9 个月了,这一次痞子衡为大家带来了版本升级 v4.0.0,这个版本主要有两个重要更新需要跟大家 ...