一、增加字体
hankaku.txt
|makefont.exe将文本文件输出为二进制文件
hankaku.bin
|bin2obj.exe将二进制文件加上连接所必需的接口信息,转换为目标程序
hankaku.obj
二、GDT(global segment descriptor table)
为了使操作系统能够同时运行多个程序,需要对内存进行分段,每一个段的起始地址都看作0来处理,为了保证程序能正常运行,就必须从物理内存中找到各个逻辑段的存放位置,为此,为每个进程建立一张段映射表,简称“段表”。
每个段对应一个段表项,段表项纪录了如下信息:
- 段的大小
- 段的起始地址
- 段的管理属性
每个段表项的长度固定,为8个字节,段表项的具体信息如下:
Segment Descriptor(段描述符):
Base(基地址):一个32位的值,包含段开始的线性地址。分为low(2字节)、mid(1字节)、high(1字节),分为三段是为了与80286时代的程序兼容,有了这样的规格,80286上的操作系统可以不用修改就在386以后的CPU上运行。
Limit(段界限):一个20位的值,以1字节单位或4KB页面表示最大可寻址单元。因此,如果选择页面粒度并将限制值设置为0xFFFFF,则该段将在32位模式下跨越整个4 GiB(2^20*4KB)地址空间。
Access Byte(访问字节,80286时代就已经存在):
Pr:段存在位,用于表示描述符所对应的段是否存在。
Pr=0,表示段不在内存中。
Pr=1,表示段在内存中。
Privl:描述符特权级别字段。包含段的CPU特权级别。0=最高权限(内核),3=最低权限(用户应用程序)。
S:用于指定描述符的类型。
S=0,表示这是一个系统段;
S=1,表示这是一个代码段或数据段(堆栈段也是特殊的数据段)。
Ex:表示是否可执行。
Ex=0,表示不可执行,数据段总是不可执行的;
Ex=1,表示可执行,代码段总是可执行的。
DC:
对于数据选择器:表示段的扩展方向。
D=0,向上扩展,即向高地址方向扩展,是普通的数据段;
D=1,向下扩展,即向低地址方向扩展,通常是堆栈段。
对于代码选择器:段特权级依从。
C=0,表示非依从的代码段,可以与特权级相同的代码段调用,或者通过门调用;
C=1,表示运行从低特权级的程序转移到该段执行。
RW:
对于数据段:段是否允许读出。
W=0,不允许写入,此时写入的话会引发异常中断;
W=1,允许写入。
对于代码段:段的写属性。
R=0,表示代码段不能读出,此时读出会引发处理器异常中断;
R=1,表示代码段可以读出。
Ac:已访问位,用于表示它指向的段最近是否被访问过。在描述符创建的时候应该清0。之后每当该段被访问时,处理器将该位置1。
常见的几种访问位:
0000000(0x00):未使用的记录表
10010010(0x92):系统专用,可读写的段,不可执行
10011010(0x9a):系统专用,可执行的段,可读不可写
11110010(0xf2):应用程序用,可读写的段,不可执行
11111010(0xfa):应用程序用,可执行的段,可读不可写
Flags(扩展访问权,80286时代还不存在):
Gr:粒度位,用于解释段界限的含义。
G=0,段界限以字节为单位,段的扩展范围为1B~1MB(描述符的界限值为20位);
G=1,段界限以页面(4KB)为单位,段的扩展范围为4KB~4GB
Sz:默认的操作数大小。主要是为了能够在32位处理器上兼容运行16位保护模式的程序。
Sz=0,表示指令中的偏移地址或者操作数是16位的;
Sz=1,表示偏移地址或者操作数是32位的。
L:64位代码段标志。如果设置为1,描述符将定义64位代码段。设置时,Sz应始终为0。对于任何其他类型的段(其他代码类型或任何数据段),将该位清0。
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; //粒度位设置为1
limit /= 0x1000; //以页面(4KB)为单位
}
sd->limit_low = limit & 0xffff; //段界限低16位
sd->base_low = base & 0xffff; //基地址低16位
sd->base_mid = (base >> 16) & 0xff; //基地址中8位
sd->access_right = ar & 0xff; //访问权
sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); //段界限高4位和扩展访问权
sd->base_high = (base >> 24) & 0xff; //基地址高8位
return;
}