快捷搜索:  汽车  科技

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)bootpack.gas : bootpack.c Makefile $(CC1) -o bootpack.gas bootpack.c graphic.gas : graphic.c Makefile $(CC1) -o graphic.gas graphic.c dsctbl.gas : dsctbl.c Makefile $(CC1) -o dsctbl.gas dsctbl.c文件名不同,执行内容雷同!简化一下#include "bootpack.h"整理MakefileMakefile内容也很长,简化一下为了解决重复填写顶部声明问题,引入了公共文件。新建:bootpack.h/* asmhead.nas */ struct BOOTINFO { char cyls; char leds; char vmode; char reser

分割bootpack.c

分割优势:内容分类管理,易于后期维护
分割劣势:文件数量增多,容易搞混

分割成三个文件

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(1)

预警!想使用naskfunc.nas的功能,每个文件都要填写顶部声明。

这样太麻烦了,后期增加内容,需要写3次!

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(2)

整理asmhead.nas

为了解决重复填写顶部声明问题,引入了公共文件。

新建:bootpack.h

/* asmhead.nas */ struct BOOTINFO { char cyls; char leds; char vmode; char reserve; short scrnx scrny; char *vram; }; #define ADR_BOOTINFO 0x00000ff0 /* naskfunc.nas */ void io_hlt(void); void io_cli(void); void io_out8(int port 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); /* 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 init_screen8(char *vram int x int y); 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); void init_mouse_cursor8(char *mouse char bc); void putblock8_8(char *vram int vxsize int pxsize int pysize int px0 int py0 char *buf int bxsize); #define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 /* 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

需要顶部声明的文件,引入公用文件即可

#include "bootpack.h"

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(3)

整理Makefile

Makefile内容也很长,简化一下

bootpack.gas : bootpack.c Makefile $(CC1) -o bootpack.gas bootpack.c graphic.gas : graphic.c Makefile $(CC1) -o graphic.gas graphic.c dsctbl.gas : dsctbl.c Makefile $(CC1) -o dsctbl.gas dsctbl.c

文件名不同,执行内容雷同!简化一下

%.gas : %.c Makefile $(CC1) -o $*.gas $*.c

去掉了具体的文件名,用文件后缀来判断具体要做的事情

bootpack.nas : bootpack.gas Makefile $(GAS2NASK) bootpack.gas bootpack.nas graphic.nas : graphic.gas Makefile $(GAS2NASK) graphic.gas graphic.nas dsctbl.nas : dsctbl.gas Makefile $(GAS2NASK) dsctbl.gas dsctbl.nas

文件名不同,执行内容雷同!简化一下

%.nas : %.gas Makefile $(GAS2NASK) $*.gas $*.na

其他文件也可以这样操作~

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(4)

意犹未尽

接着讲讲naskfunc.nas内容

_load_gdtr: ; void load_gdtr(int limit int addr); ; 段上限limit和地址数据 MOV AX [ESP 4] MOV [ESP 6] AX LGDT [ESP 6] RET

GDTR是一个很特别的48位寄存器
不能用MOV 指令来赋值。
唯一的方法就是先指定一个内存地址,然后从指定的地址读取6个字节(也就是48位),最后赋值给GDTR寄存器。
完成这一任务的指令就是LGDT。

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(5)

再讲讲dsctbl.c内容(这是bootpack.c分割出来的文件)

struct SEGMENT_DESCRIPTOR { short limit_low base_low; char base_mid access_right; char limit_high base_high; }; 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; }

这个功能是按照CPU的规格要求,将段的信息归结成8个字节写入内存的。
这8个字节里到底填入了什么内容呢

  • 段的上限(最大4GB)
  • 段的基址(32位bit=low16位bit mid8位bit high8位bit)
  • 段的访问权属性(禁止写入,禁止执行,系统专用等)

CPU到底是处于系统模式还是应用模式,取决于执行中的应用程序是位 于访问权为0x9a的段,还是位于访问权为0xfa的段

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(6)

初始化PIC
  • 想要移动鼠标?必须使用中断!
  • 想要使用中断?将GDT和IDT正确无误地初始化!
  • 想要使用中断?将PIC正确无误地初始化!

所谓PIC是“programmable interrupt controller”的缩写,意思是“可编程中断控制器”。
在设计上,CPU单独只能处理一个中断,这不够用!
所以增设了几个辅助芯片,中断信号共有15个,PIC共有2个。

PIC是将8个中断信号集合成一个中断信号的装置。
只要有一个中断信号进来,就将唯一的输出管脚信号变成ON,并通知给CPU。

从CPU的角度来看,PIC是外部设备,CPU使用OUT指令进行操作。
PIC内部有很多寄存器,用端口号码对彼此进行区别,端口写在bootpack.h文件中

更新:bootpack.h

/* int.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

引用端口

新建:int.c文件(老规矩,先建txt,改后缀)

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

最后在bootpack.c文件中调用

#include "bootpack.h" #include <stdio.h> void HariMain(void) { init_gdtidt(); init_pic(); ......代码脑补 }

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(7)

制作中断处理

前面讲了很多理论,该制作中断处理功能

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(8)

鼠标是IRQ12,键盘是 IRQ1

所以我们编写了用于INT 0x2c和INT 0x21的中断处理程序

更新:int.c

/*------------键盘-----------------*/ void inthandler21(int *esp) { struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; boxfill8(binfo->vram binfo->scrnx COL8_000000 0 0 32 * 8 - 1 15); putfonts8_asc(binfo->vram binfo->scrnx 0 0 COL8_FFFFFF "hello world my keyboard"); for (;;) { io_hlt(); } } /*---------------鼠标------------*/ void inthandler2c(int *esp) { struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; boxfill8(binfo->vram binfo->scrnx COL8_000000 0 0 32 * 8 - 1 15); putfonts8_asc(binfo->vram binfo->scrnx 0 0 COL8_FFFFFF "hello world my mouse"); for (;;) { io_hlt(); } }

更新:bootpack.c

#include "bootpack.h" #include <stdio.h> void HariMain(void){ io_out8(PIC0_IMR 0xf9); io_out8(PIC1_IMR 0xef); ....脑补代码 }

此时还有问题,C语言无法解决,所以搬来汇编救场

更新:naskfun.nas

EXTERN _inthandler21 _inthandler2c _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

push和pop叫做栈(stack)
起到临时救场,俗称缓冲区(buffer)
比如一下子涌入大量信息,先到缓冲区排队,然后再读取。
先进入缓冲区的不一定先读取,还可以最后读取,所以使用时要搞清楚缓冲区类型。

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(9)

说了这么多,是驴子是马拉出来走走

测试:打开cmd,输入make run

此时按下键盘上的任意键,出现了设置的文字 键盘输入成功!

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(10)

嗨~ 各位老铁们

鼠标移到窗口内,点击一下左键,进入到了咱们的操作系统世界

发现鼠标没反应,这是因为还需要设置其他内容,今天肯定是别想移动了。

按住ctrl alt可以切换到windows系统

今天就到这里,洗洗睡了

操作系统简单轮转调度算法的原理(第06天分割文件中断处理30天自制操作系统学习笔记)(11)

猜您喜欢: