把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. vue3.0使用tui.image-editor图片编辑组件报错TypeError: Cannot convert undefined or null to object

    在vue3.0的项目中使用tui.image-editor组件.一直都是报错.查看报错位置发现代码 addEventListener() { Object.keys(this.$listeners). ...

  2. ElasticSearch7.6.1学习笔记-狂神

    ElasticSearch:7.6.1 https://gitee.com/yujie.louis/elastic-search 笔记,代码,安装包等 什么是ElasticSearch? Elasti ...

  3. Sqoop的介绍和安装

    sqoop下载地址:https://share.weiyun.com/woVbfnfS 或者 https://archive.apache.org/dist/sqoop/1.99.7/ Sqoop简介 ...

  4. NOIP 口胡

    因为没准备啥东西 这两天口胡一下近年 NOIP 的题 大概会一道不落?没什么很寄的考点主要是 2021 T1 报数 打一个 \(O(\log n)\) 查询 \(n\) 中是否有 \(7\),打一个类 ...

  5. 手摸手,使用Dart语言开发后端应用,来吧!

    前言 这几天连续发了几篇关于 Dart 开发后端应用的文章,主要是介绍了 Dart 的一些优点,比如异步任务,并发处理,编译部署等等. 俗话说,光说不练假把式,今天我们来真正开始一个 Dart 后端应 ...

  6. 9、手写一个starter

    一.starte详解: 1.starter场景启动器: SpringBoot-starter是一个集成接合器,主要完成两件事: (1).引入模块所需的相关jar包 (2).自动配置各自模块所需的属性 ...

  7. 数值计算:前向和反向自动微分(Python实现)

    1 自动微分 我们在<数值分析>课程中已经学过许多经典的数值微分方法.许多经典的数值微分算法非常快,因为它们只需要计算差商.然而,他们的主要缺点在于他们是数值的,这意味着有限的算术精度和不 ...

  8. CH9120/CH9121 WCH-ETH透传芯片(持续更新)

    网络变压器中心抽头: 如果使用网络变压器,变压器的中心抽头需要看PHY芯片时电流型还是电压型. 如果是电压型,则需要通过一个电容直接接到GND. 如果时电流型的PHY,那么就需要根据PHY芯片来看,从 ...

  9. 克拉玛依初赛-wp

    MISC 签到 16进制转字符串 base64 再来一次base64 flag 论禅论道 7z解压得到jar 使用decom打开 解密 得到flag WEB pingme 抓包,修改POST提交的参数 ...

  10. ionic+vue+capacitor系列笔记--02项目中集成Capacitor,添加android,ios平台,真机运行项目

    Capacitor是什么? Capacitor是由ionic团队开发的一款跨平台移动应用构建工具,可轻让我们轻松的构建Android.iOS.Electron和Web应用程序. Capacitor是A ...