宏并不是 CPU 提供的指令,而是像 NASM 等编译器提供的语法。

简单点的,%define Video 0xb8000

复杂点的

1
2
3
4
5
%define PGE_2M_PDE_ATTR (PAGE_2M_MBO + \
PAGE_ACCESSED + \
PAGE_DIRTY + \
PAGE_READ_WRITE + \
PAGE_PRESENT)

代码中使用 PGE_2M_PDE_ATTR 跟后面的表达式是一样的。

条件汇编

1
2
3
4
%define ToyOS
%ifdef ToyOS
add NB, 250
%endif

%ifdef 即 if define,如果定义了某某

更多语法

%assign i 0 赋值

1
2
3
%rep 5  ;循环次数
add NB, 250
%endrep

页表定义的代码

此处的页大小为 2MB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
BITS 64 ;编译为64位代码

%define ALIGN_TOP_TO_4K_FOR_PAGING ;顶部 4K 对齐

%define PAGE_PRESENT 0x01 ;0b1
%define PAGE_READ_WRITE 0x02 ;0b10
%define PAGE_USER_SUPERVISOR 0x04 ;0b100
%define PAGE_WRITE_THROUGH 0x08 ;0b1000
%define PAGE_CACHE_DISABLE 0x010 ;0b10000
%define PAGE_ACCESSED 0x020 ;0b100000
%define PAGE_DIRTY 0x040 ;0b1000000
%define PAGE_PAT 0x080 ;0b10000000
;sum=0b11111111
%define PAGE_GLOBAL 0x0100
%define PAGE_2M_MBO 0x080
%define PAGE_2M_PAT 0x01000

; PDE 的前 8 位
%define PAGE_2M_PDE_ATTR (PAGE_2M_MBO + \
PAGE_ACCESSED + PAGE_DIRTY + \
PAGE_READ_WRITE + PAGE_PRESENT)

%define PAGE_PDP_ATTR (PAGE_ACCESSED + \
PAGE_READ_WRITE + PAGE_PRESENT)
; 计算相对页表起始的偏移,TopLevelPageDirectory 是页表起始地址
; x 是当前行的地址,二指相减就是当前行相对于页表起始地址的偏移
%define PGTBLS_OFFSET(x) ((x) - TopLevelPageDirectory)

; ADDR_OF 用于取括号里对象的16位的地址
%define PGTBLS_ADDR(x) (ADDR_OF(TopLevelPageDirectory) + (x))

; 用于定义 PML4E 以及 PDPTE
%define PDP(offset) (ADDR_OF(TopLevelPageDirectory) + (offset) + PAGE_PDP_ATTR)

参考PageTables2M.asm

EDK2

EDK2 是一个开发库,它是 UEFI 标准的实现,很多大公司为它贡献代码。

UEFI 是一套标准,就像房子的图纸,而 EDK2 是按照这个图纸造好的房子。可以说,UEFI 标准就是 EDK2 的说明文档。

这里提供一个博客从零开始的UEFI裸机编程

总结

《汇编语言学习记录》系列文章写到这里已经是第七篇了,写它的目的是学习计算机底层的基础知识,从而为搭建一个操作系统打下基础。接下来,我们就要进入一个全新的部分了,这一部分将遵从 UEFI 标准,开始搭建一个真正的 64 位操作系统 ShuangOS。我准备把接下来的部分命名为《程序员的三大浪漫之操作系统篇》