harib03a:
  内容没有变化 ;P109 从这里开始,代码开始工程化了.
  将原本300多行的bootpack.c分割成了三部分:
        graphic.c      : 用来处理界面图像
        dsctbl.c        : 用来处理中断和段表(GDT,IDT)等
        bootpack.c    : 和后面的bootpack.h文件一起用来封装函数
  修改了Makefile中的文件生成步骤(当然后面需要bootpack.h 头文件):
    修改前:bootpack.c-->bootpack.bim
    修改后:graphic.c  -->graphic.obj
        dsctbl.c    -->dsctbl.obj
        bootpack.c-->bootpack.obj
        graphic.obj+dsctbl.obj+bootpack.obj+其他接口信息-->bootpack.bim
harib03b:
  整理Makefile;简化了Makefile中的一些内容;
  感觉原理和DBMS中的LIKE字符串匹配神似,有木有。
  看看这个书本上的这个例子:归纳成一般规则:

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

harib03c:
  P111 整理头文件;这里实际上还是在做代码优化工作;为后续准备
  我们发现bootpack.c被分割之后,经常需要调用bootpack.c中的函数
  因此,来了一个头文件bootpack.h;把bootpack.c中实现的函数封装起来
  这样每次需要调用函数时只要#include一个bootpack.h 就 OK了!!

/* bootpack.h */
struct BOOTINFO { /* 0x0ff0-0x0fff */
char cyls; /* 启动区读硬盘停止的位置 */
char leds; /* 启动时,键盘LED的状态 */
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);
/* Cgraphic.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);

  接下来我们来看下LGDT和LIDT是怎么个情况:

  LGDT和LIDT都是分别是给48为的段寄存器GDTR和48位的中断寄存器IDTR赋值,他们的原理基本相同;下面以LGDT为例详细说明一下。

  1、段信息结构体struct SEGMENT_DESCRIPTOR (如下图所示)

    • 包括段的大小;
    • 段的起始地址;
    • 段的管理属性;

    

  按照CPU的结构要求,将段信息归结成8个字节写入内存中;之后再由指令LGDT装入段寄存器GDTR中;

  注意:寄存器GDTR长度为6个字节。写入段寄存器中的信息只是短信息(8个字节)中的高位的6个字节,后面两个字节存储的是段的管理属性-access_right ;

//请对照上面图片看;
//表示段信息的结构体(一共48位)
//段地址 32位:base_low(2字节)+base_mid(1字节)+base_high(1字节)
//剩余4个字节||||我们知道段上限为4GB;一个32位的数值
//如果剩余这4个字节全部用来表示段上限那么就没有空间表示段信息了;
//HOW TO DO??
//段上限 20位:段属性中的标志位Gbit为1时,limit的单位不解释成字节,而翻译成页(1页=4KB)
// limit_low 和limit_high
//注 意:limit_high中的上4位写的是段属性
struct SEGMENT_DESCRIPTOR { //段信息结构体定义8字节
short limit_low, base_low; //2字节
char base_mid, access_right; //1字节
char limit_high, base_high; //1字节
};
struct GATE_DESCRIPTOR { //中断信息结构体定义8字节
short offset_low, selector;
char dw_count, access_right;
short offset_high;
};
/*将段信息的8个字节写入内存;便于段寄存器读取;
;struct SEGMENT_DESCRIPTOR 在头文件中;
;段大小;;段起始地址;;段的管理属性(写入,执行,系统专用等) */
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 >> ) & 0xff;
sd->access_right = ar & 0xff;
sd->limit_high = ((limit >> ) & 0x0f) | ((ar >> ) & 0xf0);
sd->base_high = (base >> ) & 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 >> ) & 0xff;
gd->access_right = ar & 0xff;
gd->offset_high = (offset >> ) & 0xffff;
return;
}

  2、LGDT和LIDT的具体实现

    

;LGDT给48位寄存器GDTR赋值;
;方法:从指定地址的高6个字节;
;底16位为段上限;高32位为GDT表开始的地址
_load_gdtr: ; void load_gdtr(int limit, int addr);
MOV AX,[ESP+] ; limit
MOV [ESP+],AX
LGDT [ESP+]
RET
;LIDT赋值,原理和上面基本相同
_load_idtr: ; void load_idtr(int limit, int addr);
MOV AX,[ESP+] ; limit
MOV [ESP+],AX
LIDT [ESP+]
RET

  3、段管理属性ar(limit_high的高四位+access_right)

    •   在段信息的结构体中,我们可以看到access_right定义类型为char,一个字节(8位);
    •   段管理属性是有两部分组成的:段上限(大小)的高四位(也就是limit_high的高四位)+access_right(8位) = 12位
    •   ar的高四位是“拓展访问权限”
    •   ar的底8位是决定系统模式和应用模式的(有用户进程和系统进程的感觉,有木有)

 harib03d:

  请对照书P117的图看  初始化PIC(programmable interrupt controller-可编程中断控制器),顾名思义:控制中断的东西

  CPU单独只能处理一个中断,因此需要辅助芯片来帮助CPU处理不同的中断信号;

  主PIC(PIC0)和CPU相连;从PIC( PIC1 )和主PIC的IRQ2相连;扩展了16个中断口

  PIC芯片的主要寄存器:

    IMR:中断屏蔽寄存器;8位,对应8路IRQ信号;信号1屏蔽该路中段;

    ICW:初始化控制数据;一共有4个寄存器

    •  ICW1:定值,由主板配线方式决定;
    •  ICW4:定值,由主板配线方式决定;
    •  ICW3:定值,主-从CPI的连接设定;(以上三个都由芯片本身的属性决定)
    •  ICW2:16位,对应从IRQ0-IRQ15;决定PIC芯片发送哪一号中断通知CPU。
/* int.c */
#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, << ); /* 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, ); /* PIC1由IRQ2连接 */
io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外的全部禁止 */
io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */
return;
}

 harib03e:

  设置键盘和鼠标中断;笔者将键盘中断设在了PIC的IRQ12,将鼠标设在了IRQ1;

   调用的终端号分别为0x2c(0010 1100) 和 0x21(0010 0001)   可以对照P117的PIC芯片图看。

void inthandler21(int *esp)
/* PS/2的键盘中断 */
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; //加载BIOS
boxfill8(binfo->vram, binfo->scrnx, COL8_000000, , , * - , );
//获取键盘中断之后,显示这个字符串INT 21 (IRQ-1) : PS/2 keyboard
putfonts8_asc(binfo->vram, binfo->scrnx, , , COL8_FFFFFF, "INT 21 (IRQ-1) : PS/2 keyboard");
for (;;) { //之后 让CPU等着 !!
io_hlt();
}
}

  下面介绍了键盘中断函数的具体实现的汇编代码;

  笔者在这里介绍了堆栈的一些知识,这段汇编代码就比较简单了:

_asm_inthandler21:
PUSH ES ;关键寄存器压栈,函数必做
PUSH DS
PUSHAD
MOV EAX,ESP
PUSH EAX
MOV AX,SS ;将DS和ES调整到与SS相等
MOV DS,AX
MOV ES,AX
CALL _inthandler21 ;调用函数_asm_inthandler21
POP EAX ;返回后,将寄存器回复原来
POPAD
POP DS
POP ES
IRETD ;最后执行IRETD

  我们已经编写了键盘的响应函void inthandler21(int *esp);也理解了该函数的汇编具体在内存中怎么做的_asm_inthandler21:

  接下来就要把键盘中断号写到中断表中,这样当执行INT时,就可以调用相应的中断程序了(在这里是函数void inthandler21(int *esp))

    /* IDT设定; */
set_gatedesc(idt + 0x21, (int) asm_inthandler21, * , AR_INTGATE32);
set_gatedesc(idt + 0x27, (int) asm_inthandler27, * , AR_INTGATE32);
set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, * , AR_INTGATE32);

  差不多了,make run 以后,只要敲了键盘,就会相应0x21中断,接着CPU会在中断表中找到这个中断程序(在这里是函数void inthandler21(int *esp))的入口了。于是就会执行这个中断程序,而这个程序的内容就是输出字符串

    INT 21 (IRQ-1) : PS/2 keyboard

《30天自制操作系统》06_day_学习笔记的更多相关文章

  1. 《30天自制操作系统》学习笔记--Mac下工具的使用

    现在来介绍官网上下的工具怎么用首先是官网地址,书上有个注释上有:hrb.osask.jp 翻译成中文大概是这个样子滴. 上面有两个文件可以下载,一个是工具,一个是工具的源代码,很好的学习资料 下面把工 ...

  2. 《30天自制操作系统》学习笔记--Mac环境搭建

    弄了三天了,终于弄好了,先说结果,就是作者在网站上放了os x的工具(hrb.osask.jp,也有linux下的工具,可以自己去下载),也就是说我白忙活了三天... 再说一下这几天都干啥了,主要是想 ...

  3. 《30天自制操作系统》学习笔记--番外篇之Mac环境下的工具介绍

    这几天又有点不务正业了,书也没看,一直在搞这个破环境,尝试各种做法,网上各种垃圾信息,浪费了很多时间,说的基本都是废话,不过还是找到了一些,赶紧写下来,不然这个过几天又忘了 首先是环境,我用的是Max ...

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

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

  5. 《30天自制操作系统》读书笔记(3) 引入C语言

    这一次的学习相当曲折, 主要是因为粗心, Makefile里面的错误导致了文件生成出现各种奇奇怪怪的问题, 弄得心力交瘁, 因此制作过程还是尽量按着作者的路子来吧. 作者提供的源码的注释在中文系统下是 ...

  6. 《30天自制操作系统》读书笔记(2)hello, world

    让系统跑起来 要写一个操作系统,我们首先要有一个储存系统的介质,原版书似乎是06年出版的,可惜那时候没有电脑,没想到作者用的还是软盘,现在的电脑谁有软驱?不得已我使用一张128M的SD卡来代替,而事实 ...

  7. 30天自制操作系统第九天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第九天的课程已学完,确实有点不想写 ...

  8. 从你的u盘启动:30天自制操作系统第四天u盘启动学习笔记

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 developing environment:ubuntu 关于u盘启动自己做的操 ...

  9. 30天自制操作系统第八天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第八天的学习思考: 关于鼠标是怎么 ...

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

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

随机推荐

  1. Yii源码阅读笔记(四)

    所有控制器action的基类yii\base\Action.php namespace yii\base;//定义的命名空间 use Yii //使用的命名空间 class Action extend ...

  2. WEB系统开发

    最近根据项目组需求做了web工作流程系统,就是一个简单的web管理系统,取代原先使用的excel表格,在VS2008下面开发,数据库使用Mysql,使用Mysql-connecte 5.0与数据库连接 ...

  3. javaWeb中struts开发——Bean标签

    1.struts标签库中常用标签 使用myeclise标签可以自动注入,其中,前三个是经常使用的,主要的是logic标签 2.Bean标签 Bean标签主要用来定义和访问JavaBean,在Strut ...

  4. Converting from Decimal Notation to Binary Notation for Fractions

    COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION Therefore, the conver ...

  5. Asp.net forms认证注意事项

    1.N台服务器配置文件的相关配置要一致 <authentication mode="Forms"> <forms timeout="3600" ...

  6. 20145319 《java程序设计》课程总结

    20145319 <Java程序设计>课程总结 读书笔记链接总结 - 20145319 第一周学习总结 - 20145319 第二周学习总结 - 20145319 第三周学习总结 - 20 ...

  7. 移动设备优先viewport

    Bootstrap 3 的设计目标是移动设备优先,然后才是桌面设备.这实际上是一个非常及时的转变,因为现在越来越多的用户使用移动设备. 为了让 Bootstrap 开发的网站对移动设备友好,确保适当的 ...

  8. php--mongodb的安装

    1.mongodb 安装 2.mongodb 扩展 http://pecl.php.net/package/mongo/1.6.14/windows

  9. 解决Eclipse启动报错Failed to create the Java Virtual Machine

    电脑:2G内存,WIN7 32位. 启动adt-bundle-windows-x86-20140702\eclipse\eclipse.exe时,报错[Failed to create the Jav ...

  10. mysql存储过程之游标遍历数据表

    原文:mysql存储过程之游标遍历数据表 今天写一个mysql存储过程,根据自己的需求要遍历一个数据表,因为对存储过程用的不多,语法不甚熟悉,加之存储过程没有调试环境,花了不少时间才慢慢弄好,故留个痕 ...