粗略阅读haribote OS 3

2016.09.04 -09.16
《haribote》-川合秀实
个人笔记。

#1 haribote
09.04
功能。从头到尾开发一个能够显示任意多的窗口、实现鼠标光标控制、能够同时运行几个应用程序的操作系统。

方式。[1] C语言为主(很少依赖操作系统 – 除依赖系统调用的库函数外);汇编为辅(用于不能用C编写的地方,如访问外部设备端口的IN/OUT;设置中断位CLI/STI;标志寄存器的读取/写入、设置GDT、IDT、中断程序返回IRETD、LTR、far跳转等)。
[2] 制作一张含有操作系统的软盘(BIOS在以软盘启动的情况下会加载执行IPL)。
[3] 改造gcc来编译操作系统程序。(以及一些其它的工具得到下载到软盘上的最终文件)

##1 day 从计算机结构到汇编程序入门
电平序列。用二进制编辑器编辑的01序列在内存中存储为低高电平序列。将内存中的该序列存储到磁盘中,该序列在磁盘中保存为磁极的N极和S极序列;反之,磁盘中的N极和S极序列被读入内存中时得到低高电平序列。

启动区(IPL,0x7c00 ~ 0x7dff)。软盘的第一个扇区被称为启动区。计算机最先读启动区并检查该区最后两个字节内容 [若为55AAH则表示软盘启动区内有启动程序加载器(IPL),并执行该区内的程序]。

##2 day 汇编语言与Makefile入门
能表示内存地址的寄存器。CPU只能用BX,BP,SI,DI来表示内存地址,剩下的寄存器不能用来表示内存地址,因为CPU内没有处理该指令的寄存器。

BIOS(Basic input output system,基本输入输出系统)。电脑里有个名为BIOS的程序,出厂时就组装在电脑主板上的ROM单元里。电脑厂家在BIOS中预先写入了操作系统开发人员经常会用到的一些程序。

HLT。HLT指令可以让CPU处于休眠状态,可以省很多电。当外部发生变化,如按下键盘,或是移动鼠标,CPU就会醒过来,继续执行相应的程序。

09.06
##3 day 进入32位模式并导入C语言
软盘。将软盘拆开,可以看到中间有一个8厘米的黑色圆盘,即一层薄薄的磁性胶片 —— 磁盘。按照以下方式组织磁盘上的数据:
这里写图片描述

以一个扇区为单位(每个扇区为512字节)读写数据。每个柱面的正、反面各有18个扇区,编号为1号 ~ 18号,共有80个柱面,编号为0号 ~ 79号。磁头0/1对应柱面的正面/反面,用于读写磁盘。

IPL的装载。IPL的启动区位于柱面0的1扇区(对应磁头0)。计算机启动后,BIOS会读该扇区的内容到0x7c00 ~ 0x7dff中(若计算机以软盘启动);然后IPL程序将软盘上的程序(包括IPL自身)加载到自0x8000开始的内存中(若IPL程序有效)。

在软盘中保存的文件的位置。一般向一个空软盘保存文件时,文件名会写在0x002600以后的地方;文件的内容会写在0x004200以后的地方。该文件在内存中的位置(地址)就应该是0x8000(IPL被加载的起始地址) + 0x4200 = 0xc200了。这样,在含操作系统的文件开头加上ORG 0xc200(操作系统程序以其所在文件开头计偏移地址),然后在IPL启动程序中加JMP 0xc200指令,就可以执行到内存中的操作系统程序了。

Intel CPU 32位模式和16位模式。[1] 16位模式和32位模式中,机器语言的命令代码不一样,同样的机器语言,解释的方法也不一样;[2] 32位模式下可以使用更大的内存(地址线);[3] 32位模式有自我保护功能;[4] 32位模式不能调用BIOS功能(因为你BIOS使用16位机器语言编写)

VRAM。VRAM指的是显卡内存,也就是能够用来显示画面的内存,其在内存分布图上有好几个不同的地方。(如BIOS INT 0x10 对应的VRAM在内存中的分布地址为0xa0000 ~ 0xaffff这64KB)

从使用汇编语言到导入C语言需要的工作。[见 通往32位模式的设置]
C语言和汇编语言的结合。计算机启动加载并执行IPL涉及到的都是汇编语言,在IPL中可以跳转到C语言对应的机器码。不管C还是汇编,被编译后(链接,C需要链接)在内存中都是机器语言。这个过程需要编译器、链接器帮忙[最终是将C和汇编文件翻译成机器码并将它们合并到一个文件中]。

##4 day C语言与画面显示的练习
调色板。由程序员给彩色模式(如8位)随意指定彩色模式(0 ~ 255的数字)指定对应颜色。比如设定彩色模式的25号对应#ffffff(RGB),26号颜色对应#123456。这种方式就叫做调色板。(不做设定,0号颜色就是#000000,15号颜色就是#ffffff)

端口/和CPU连接的除内存的外部设备。既然CPU与设备相连,那么就有向这些设备发送电信号,或者从这些设备取得信息的指令。向设备发送电信号的是OUT指令;从设备取得电气信号的IN指令。正如为了却别不同内存要使用内存地址一样,在OUT指令和IN指令中,为了却别不同的设备,也要使用设备号码。设备号码在应为中称为端口

显示屏幕跟VRAM(显存)地址的关系。一般来说,屏幕的左上点坐标(0, 0)对应某种模式下VRAM的开始的地址(如0xa0000)。然后屏幕(假设为320 x 200像素)上的像素(x, y)对应的VRAM地址为0xa0000 + x + y * 320。往0xa0000 + x + y * 320中写入的颜色就会显示在屏幕的(x, y)处。

09.08
32位模式下显示字符。16位模式下可以调用BIOS来显示字符。在32位模式下,可以先在像素点阵(如8 x 16)中用点表示出字符的形状,将像素点阵中有字符形状的点用1代替,无字符形状的点用0表示(或者相反)。然后根据这些数据在屏幕上打上点就能显示出该字符了。[显存的一(多)个字节对应屏幕上(字符形状)的一个像素点]

##5 day 结构体 文字显示与GDT/IDT初始化
OSASK中使用的字体。编码(如图形方式)每一个字符(ASCII集,256个字符),然后通过将这些编码翻译成字符相应的像素点阵(二进制文件hankaku,每个字符在该文件中有规律,如’A’在hankaku + ‘A’ * 16开始的16字节里)

鼠标光标显示。思路跟显示字符一样。首先选取像素点阵来描绘鼠标图形,确定像素点阵各部分中各部分颜色,然后将像素点阵中相应颜色写入对应的显存地址中即可。

09.09
分段/分页
所谓分段,打个比方说,就是按照自己喜欢的方式,将合计4GB的内存分成很多块,每一块的起始地址都看着0来处理。这很方便,有了这个功能,任何程序都可以先写上一句ORG 0。像这样分割出来的块,就称为。采用分页的方式也能达相同效果。

CPU保护模式下段的相关设定
[1] 用段寄存器来存储段号。段寄存器的高13位来存储段号(CPU 32位模式下的段寄存器仍然是16位的,且低3位不能使用),能够存储8192个段号。
[2] CPU用8个字节的数据来表示一个段的信息[在保护模式下,分这样一个段需要以下段信息:段的大小;段的起始地址;段的管理属性,如禁写、禁执行,系统专用等]。8192个段就需要 8192 x 8 = 2 1 3 x 2 3 = 2 1 6 = 64 K B 8192 x 8 = 2^13 x 2^3 = 2^16 = 64KB 8192x8=213x23=216=64KB存储空间,这64KB内容被存储在内存中,即GDT[global (segment) descriptor table]。[观察内存地址空间分布,选取一段未使用的内存段来作为GDT]
[3] 将GDT的起始地址和GDT中所保存的段信息的有效个数放在CPU内的GDTR寄存器中。

CPU保护模式下访问内存方式(CPU自动完成):根据段寄存器的段号n,结合GDTR寄存器中所保存的GDT的起始地址add,可以得到段号为n的段信息地址add + n x 8(段号从0开始),然后就从段信息中获取到段号为n的段在内存中的起始地址以及段大小、属性等信息,然后就可以去访问段号n所对应的段内存了。[操作系统的加载程序在将程序加载到物理内存时,先为其寻找一块空闲的段内存,然后根据程序中ORG伪指令指定的偏移地址off,从该段内存的off偏移处开始加载/复制程序]
关于IDT(interrupt descriptor table,中断记录表)的设定和机制跟GDT差不多。差别是,IDT的中断号由中断信息携带,根据该中断号就可以到IDT中寻找到相应中断函数的地址。

##6 day 分割编译与中断处理
汇编函数参数。汇编函数参数直接从栈里取。[esp指向的是旧的ebp的值,接下来指向各个参数,参数顺序从左到右(具体顺序依编译器而定)]

GDT内段信息。段信息共8个字节;段大小信息占用20位信息;段地址占用32位;段属性占用12位(高4位CD00称为扩展访问权,高两位分别对应Gbit和段模式;低8位用于设定段的使用权的所有者或可读/写与否;如0x92和0x9a用于设定系统专用的段,分别对应可读写和可执行的段;0xf2和0xfa用于设定应用程序段,分别对应可读写段和可执行段)。段属性里有一个标志位,叫做Gbit,这个标志位为1的时候,段的大小的单位不再为字节而是为页(一般为4KB),那么段的大小就可以为 1 M ( 2 2 0 ) x 4 K B = 4 G B 1M(2^20) x 4KB = 4GB 1M220x4KB=4GB。段信息在这8字节中分别对应的位得查看CPU关于段信息的手册。

PIC(programmable interrupt controller,可编程中断控制器)。PIC是将8个中断信号(interrupt request,IRQ)集合成一个中断信号的装置。PIC监视着输入管脚的8个中断信号,只要有一个中断信号进来,就将唯一的输出管脚信号变成ON,并通知给CPU。IBM的大叔们想要通过增加PIC来处理更多的中断信号,他们认为电脑会有8个以上的外部设备,所以就把中断信号设计成了15个,并为此增设了2个PIC。
这里写图片描述

PIC的寄存器。PIC对于CPU来说是外部设备,其内的寄存器(都是8位)由端口号码区分。IMR(interrupt mast register,中断屏蔽寄存器)每一位对应一路IRQ信号。如果某一位的值是1,则该位所对应的IRQ信号被屏蔽,PIC就忽视该路信号。ICW(initial control word,初始化控制数据)寄存器一共有4个。ICW1和ICW4与主板配线方式、中断信号的电气特性有关(一般为固定值)。ICW3是有关主-从连接的设定,对主PIC而言,第几号IRQ与从PIC相连,是用8位来设定的。对于从PIC来说,该从PIC与主PIC的第几号相连。ICW2用来设定IRQ以哪一号中断通知CPU [如键盘和鼠标中断分别是IRQ1和IRQ12,可以为这两个中断指定中断分别指定中断号0x21和0x2c] [《CSAPP》中述说的其余异常号由编写操作系统的人儿就是这个意思]

CPU与PIC数据传输。中断发生以后,如果CPU可以受理这个中断,CPU就会命令PIC发送2个字节的数据。CPU与PIC用IN或OUT进行数据传送时,有数据信号线连接在一起。PIC就是利用该信号线发送这两个数据的。送过来的数据是“0xcd 0x??”这两个字节。由于电路设计的原因,这两个字节的数据在CPU看来,与从内存读进来的程序是完全一样,所以CPU就把送过来的“0xcd 0x??”作为机器语言执行。这恰恰就是把数据当作程序来执行的情况。这里的0xcd就是调用BIOS使用的那个INT指令。

PIC上允许的中断号。0x00 ~ 0x1f是CPU内部会自动产生INT 0x00 ~ 0x1f的中断号(由设计CPU的人儿定)。

中断发生到中断函数过程。PIC的输入管脚检测到中断发生,如果CPU受理该中断,该引脚上的中断信息[INT 中断号(配置PIC的ICW2寄存器可以配置该引脚的中断号)]就会被发送给CPU当成指令执行。即CPU会跳转到IDTR中保存的IDT地址 + n x 4去执行该中断对应的中断处理程序。[IDT中的中断程序地址和PIC中设定的中断号要一一对应]

中断程序的入口只能由汇编编写。因为从中断程序中返回需要使用IRETD指令,而C语言无与IRETD指令相对应的语句,所以只能在汇编函数中调用C函数 [按照编译器处理C标识符的规律调用C函数]。

CALL-RET和INT-IRETD区别。CALL [CS、IP入栈;将CS和IP的值分别设为标号所在段的段地址和偏移地址] – RET [IP、CS出栈];INT [取中断号n;标志寄存器入栈,IF=TF=0;CS、IP入栈;(IP) = (n * 4),(CS) = (n * 4 + 2)] - IRETD [IP、CS出栈;标志寄存器出栈]。

PIC被继续监视的特点。在接收到PIC某引脚中断后,要用程序告知PIC继续监视该引脚的中断,否则PIC不再理该引脚上的中断。

##7 day FIFO与鼠标控制
为什么不在中断函数里执行过多的语句。所谓中断处理,基本上就是打断CPU本来的工作,然后让CPU转去执行别的处理,所以中断过程必须完成得干净利索。而且在中断处理期间,不再接受别的干扰。所以如果中断处理过慢(如键盘中断函数),就会影响其它操作(如鼠标)。所以需要分析中断函数中处理的指令是否过多,若过多,则应将在中断函数里所接收的数据保存在缓冲区里面,在退出中断处理函数后再处理缓冲区中的数据。

FIFO结构以及管理FIFO的结构体
这里写图片描述

struct FIFO8 {
	unsigned char *buf;
	int p, q, size, free, flags;
}

鼠标中断设置分为两部分。一部分是包含在键盘控制电路里的鼠标控制电路,另一部分是鼠标本身。

##8 day 鼠标控制与32位模式切换
09.10
鼠标数据组成。鼠标产生中断时,最初会发0xfa这个数据。之后,每次从鼠标那里送过来的正常数据都应该是3个字节一组的。第一字节的高4位在移动鼠标时会在0 ~ 3的范围内变化;低四位在鼠标点击(左右击以及击中间滚轮)时会有变化,变化范围为8 ~ F [特别地,鼠标键的状态为低三位]。第二个字节跟鼠标的左右移动有关系。第三个自己跟鼠标的上下移动有关系。[鼠标移动的数据需要跟第一字节中对鼠标移动有反应的即为信息,将左右移或者上下移中的数据的第8位以及第8位以后全部都设置为1或0]

鼠标数据处理。[1] 在鼠标中断函数中将鼠标数据存储在FIFO缓存区中;[2] 在主程序中查询鼠标缓冲区FIFO区的内容,每三字节内容解析(舍弃不在鼠标数据范围的数据;)一次。

通往32位模式的设置
[1] 设置主/从PIC关闭所有的外中断,禁止CPU级别的所有中断;
[2] 设定A20GATE,让CPU能够访问1MB以上的内存空间;
[3] 通知编译器即将使用386以后的指令,设定临时的GDT;
[4] 确定内存空间的分布图(将相应程序、文件拷贝到相应的内存空间,见总结),OSASK的内存分布图如下

内存空间内容
0x00000000 - 0x000fffff启动中会多次使用(用来保存磁盘中的内容),之后就不再使用,含BIOS和VRAM相关的内容(1MB)
0x00100000 - 0x00267fff用于保存软盘的内容(1440KB)
0x00268000 - 0x0026f7ff空(30KB)
0x0026f800 - 0x0026ffffIDT(2KB)
0x00270000 - 0x0027ffffGDT(64KB)
0x00280000 - 0x002fffffbootpack.hrb(512KB)
0x00300000 - 0x003fffff栈及其他(1MB)
0x00400000 - 空(30KB)

##1-8 days 总结
如何开发OSASK
[1] 在windows上编写源代码;
[2] 用编译器将源代码编译成机器码;
[3] 对机器码文件加工,生成软盘映像文件;
[4] 将映像文件写入磁盘,做成含操作系统的启动盘。

OSASK程序组成/执行流程 – [3, 4]
这里写图片描述

[1] OSASK映像文件总大小不到80KB。[磁盘一共1440KB,所以可以容纳OSASK映像文件]
[2] 在实模式下,IPL将映像文件拷贝到始于内存0x8000(IPL最初被读到0x7c00 ~ 0x7dff处,带IPL执行后,IPL又存在于0x8000 ~ 0x81ff处)以后的1440KB内存空间 [BIOS会自动读磁盘的IPL到内存0x7c00 ~ 0x7dff处,并检查IPL最后两个字节,如果为0x55AA,则执行IPL,IPL会将磁盘内容拷贝到始于内存0x800的内存空间中。那么,运行保存到映像文件中的OSASK代码时,需要跳转到0x8000 + 0x004200 = 0xc200处]
[3] 若要进入保护模式:IPL执行完毕后,会跳转到从实模式进入32位模式的代码(即asmhead.nas,即内存0xc200处)。从实模式进入保护模式的代码将内存空间0x7c00 ~ 0x7dff的IPL程序拷贝到0x00100000~0x001001ff处,再将始于内存空间0x8200的(1440KB – 512bytes)内容拷贝到始于0x00100200处的内存空间中。到此,磁盘中的1440KB内容就保存到了内存空间0x0010000 ~ 0x00267fff中。接下来,再单独(磁盘的其余内容被仍被保存在0x0010000 ~ 0x00267fff中)将bootpack.c的内容(在asmhead.nas之后:asmhead.nas和bootpack.c经编译、连接后形成一个文件被保存到映像文件中)拷贝到始于0x00280000的512KB(留有多余空间)空间中,asmhead.nas程序执行完毕后将跳转到0x00280000处,即执行bootpack.hrb的内容]

内容
[0] 内存空间分布
[1] IPL;
[2] GDT/IDT/PIC的初始化;
[3] 栈和FIFO缓冲区的使用;[FIFO中的数据:0~1用于光标闪烁定时器;3用于3秒定时器……;256 ~ 511用于键盘输入(从键盘控制器读入的值再加上256);512 ~ 767用于鼠标输入(从键盘控制器的鼠标相关的控制器中读入的值加上512)]
[4] 键盘中断的处理。

##9 day 内存管理
内存容量检查。在最初启动时,BIOS会检查内存容量。因为在保护模式下调用BIOS会比较麻烦,所以作者打算自己检查内存容量:往内存里随便写入一个值,然后马上读取,检查读取的值与写入的值是否相等;如果内存连接正常,则写入的值能够记在内存里;如果没连接上,则读出的值肯定是乱七八糟的。
[1] 让486 CPU高速缓存(cache)功能无效(检查标志寄存器的18位是否为1,若为1则设置CR0寄存器中标记缓存的位);[如有缓存,写入和读出的不是内存,而是缓存。结果,所有的内存都“正常”,检查处理不能正确被完成]
[2] 以4KB为单位,检查每4KB末尾的4个字节;
[3] 防止C编译器对内存读写语句的优化(可用汇编编写这段程序);

内存管理。假设内存大小是128KB,应用程序A暂时需要100KB,画面控制需要1.2MB……,像这样,操作系统在工作中,有时需要分配一定大小的内存,用完以后又不在需要,这种事会频繁发生。为了应付这些需求,必须恰当管理好哪些内存可以使用,哪些内存不可以使用,这就是内存管理。

内存管理方法。内存管理的基础,一是内存分配,一是内存释放。
这里写图片描述

这里写图片描述

##10 day 图层叠加处理
这里写图片描述

这里写图片描述

##11 day 制作窗口
这里写图片描述

这里写图片描述

##12-13 day 定时器
PIT(Programmable Interval Timer,可编程的时间间隔定时器)。通过设定PIT,定时器就可以每个多少秒就产生一次中断(PIT连接着IRQ0)。通过设置PIT端口就可以设定PIT,如PIT产生中断的频率(中断频率是单位时间时钟周期数即主频/PIT设定的中断周期的数值,如主频为1193.18KHz,PIT中断周期设定值为1000,则IRQ0中断产生频率为1.19318KHz)。

超时(timeout)。定时器计时达到一段时间(如30s,5个月)时就发出一个通知,这样的功能被称为超时。
这里写图片描述

这里写图片描述

##9-13 days 总结
[1] 一般来说,关于数据结构:描述对象的结构体 + 管理描述对象的结构体。
[2] 对于常被运行(如定时器中断函数)的函数,对其性能提升一点都可能会很有意义。
[3] 因为C编译器的问题,由于跳转目标地址不同,CPU的JMP指令执行的时钟周期不同(汇编则不会有此问题)。

##14 day 高分辨率并处理键盘数据
高分辨率的利用方法因显卡不同而不同。不同显卡提供不同的BIOS设置方法(这就得修改在进入保护模式前设置画面的汇编程序,调用显卡的BIOS来设置画面)

VBE(Video Electronics Standards Association BIOS extension,VESA-BIOS扩展,简略称为VBE),利用VBE,就可以使用显卡的高分辨率功能了。在设置该画面前,要检测该真机是否支持VBE的特定版本(若不能,就只能使用旧式320 x 200的画面了)
这里写图片描述

这里写图片描述

##15-16 day 多任务
多任务。多个应用程序“同时运行”的状态就叫做多任务(多进程)。

多任务切换。在一般的操作系统中,多任务(多进程)间切换的动作每0.01 ~ 0.03秒就会进行一次。[当然,切换的速度越快,让人觉得程序是在同时运行的效果也就越好。CPU进行任务切换这个动作本身就需要消耗一定的时间,这个时间大约为0.0001s左右,不同的CPU及操作系统所需的时间也有所不同。如果CPU每0.0002s就切换一次任务的话,该CPU处理能力的50%都要被任务切换本身所消耗掉。所以,如果每0.01s完成一次切换,任务切换时间就只有1%了,可以忽略不计了]
这里写图片描述

09.14
CPU切换任务保存的上下文。当向CPU发出任务切换的指令,CPU会把寄存器中的值全部写入内存中,这样做是为了当以后切换回这个程序的时候,可以从中断的地方继续运行。接下来,为了运行下一个程序,CPU会把所有寄存器中的值从内存中读取出来(当然,这个读取的地址和刚刚写入的地址一定是不同的,不然就相当于什么都没变嘛),这样就完成了一次切换。任务切换所需要的时间,正是对内存进行写入和读取操作所消耗的时间。

CPU切换任务原理如果一条JMP指定的目标地址段不是可执行的代码,而是TSS的话,CPU就不会执行通常的改写EIP和CS的操作,而是将这条指令理解为任务切换。也就是说,CPU会切换到目标TSS所指定的任务

指定TSS。一个段的含义由其段属性指明,只要将保存TSS信息所在段的段属性指定为保存任务切换信息的段即可。
这里写图片描述

这里写图片描述

09.15
##17-27 day 外壳 API 保护操作系统 应用程序 保护应用程序
FAT(file allocation table,文件分配表)。用来记录文件在磁盘中存放位置的表。按照windows管理磁盘的方法,保存大于512字节的文件时,有时候并不是存入连续的扇区中。这就得依靠FAT来找到文件后续内容在哪一个扇区中。
这里写图片描述
这里写图片描述

为什么要保护操作系统。应用程序可能存在bug,它们可能对操作系统造成破坏。比如擅自删除重要文件、使其它任务的运行产生异常,或者造成操作系统死机而不得不重新启动等。操作系统为应用程序的运行提供了支持,也考虑了如何对待这样的问题,即提供了保护操作系统的功能。

异常。在0x86架构规范中,当应用程序试图破坏操作系统,或者试图违背操作系统的设置时,就会自动产生0x0d中断,因此该中断被称为异常。(段属性)在定义段的地方,如果将权限加上0x60的话,就可以将段设置为应用程序用。当CS中的段地址为应用程序段地址时,CPU会认为当前正在运行应用程序,这时如果存入操作系统用的段地址就会产生异常。
这里写图片描述

09.16
LDT[local (segment) descriptor table,局部段描述符表]。GDT中的段设置是提供给所有任务通用的,而LDT中的段设置则只对某个应用程序有效。如果将应用程序段设置在LDT中,其他的应用程序就无法使用该LDT指定的段了
这里写图片描述
。将很多个.obj文件打包(使用库管理器程序)成一个文件,就叫库(广泛讲,可以作为一个部件使用的都叫库)。[库中包含多个.obj文件即多个函数集合,但源程序中只会添加库中被调用的函数的目标代码]
结构化编程技术。[1] 将整体模块化;[2] 模块化的可重利用。

##28 day 文件操作-应用程序调用系统调用或库实现功能
这里写图片描述

#2 OASK_rw_before
之前胡乱涉及的笔记。
----[x86实模式] 内存地址空间分布 CPU合成内存地址的方式 程序中段的加载 启动区格式要求----
[Rx86OS-I] 计算机开机从软盘启动显示字符串Hello World
[Rx86OS-II] 制作IPL
----[x86保护模式] CPU合成内存地址的方式----
[Rx86OS-III] 由实模式切换到保护模式
[Rx86OS-IV] 导入32位C语言
[Rx86OS-IV] 用C语言实现画面(颜色)
[Rx86OS-V] 像素点阵字符串和鼠标图标
[Rx86OS-VI] 实现鼠标中断
[Rx86OS-VII] 接收鼠标数据
[Rx86OS-VIII] 解读鼠标数据 移动鼠标
[Rx86OS-IX] 内存管理•简
[Rx86OS-X] 图层叠加处理I
[Rx86OS-XI] 图层叠加处理II(高速刷新图层时的闪烁处理)
[Rx86OS-XII] 使用定时器 (通路 设计 优化)过程 (线性表)
[Rx86OS-XIII] 提高分辨率
[Rx86OS-XIV] 键盘输入处理
(http://blog.csdn.net/misskissc/article/details/45224613)
[Rx86OS-XV] 实现多任务
[Rx86OS-XVI] 制作命令行窗口I(键盘输入)
[Rx86OS-XVII] 制作命令行窗口II(命令)
[Rx86OS-XVIII] 应用程序和系统调用
[Rx86OS-XIX] x86保护操作系机制 (异常处理) 保护应用程序机制 库
读OSASKII

[2016.10.01 - 08:57]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值