├── .gitignore ├── README.md ├── advanced ├── cpuid.s └── makefile ├── assembly.code-workspace ├── language ├── chapter_04 │ ├── error_01.asm │ ├── experiment_3.asm │ ├── first_01.asm │ └── first_02.asm ├── chapter_05 │ ├── example_1.asm │ ├── example_5.3.asm │ ├── example_5.7.asm │ ├── example_loop.asm │ └── experiment.asm ├── chapter_06 │ ├── example_1.asm │ ├── example_2.asm │ ├── example_3.asm │ ├── example_4.asm │ └── experiment.asm ├── chapter_07 │ ├── example_1.asm │ └── example_2.asm ├── chapter_08 │ ├── example_1.asm │ └── experiment.asm ├── chapter_09 │ ├── exam_1.asm │ ├── example_01.asm │ ├── example_02.asm │ ├── example_03.asm │ ├── example_04.asm │ ├── example_05.asm │ ├── experiment_1.asm │ └── experiment_2.asm ├── chapter_10 │ ├── exam_01.asm │ ├── exam_05.asm │ ├── example_01.asm │ ├── example_02.asm │ ├── example_03.asm │ ├── example_04.asm │ ├── example_05.asm │ ├── example_06.asm │ ├── example_07.asm │ └── experiment_01.asm ├── chapter_11 │ ├── example_01.asm │ ├── example_02.asm │ ├── example_03.asm │ ├── example_04.asm │ ├── example_05.asm │ └── experiment_11.asm ├── chapter_12 │ ├── example_01.asm │ └── example_02.asm ├── chapter_13 │ ├── example_01.asm │ ├── example_02.asm │ ├── example_02_install.asm │ ├── example_03.asm │ ├── example_03_install.asm │ ├── example_bios.asm │ ├── example_dos.asm │ ├── experiment_1.asm │ └── experiment_1_install.asm ├── chapter_14 │ └── example_01.asm └── chapter_15 │ ├── example_01.asm │ ├── example_02.asm │ ├── example_03.asm │ ├── example_int9.asm │ ├── example_int9_install.asm │ └── experiment_01.asm ├── note ├── 8086 CPU 相关寄存器.md └── 8086 数据类型.md ├── os ├── bochsrc ├── makefile └── src │ ├── boot │ ├── boot.asm │ ├── boot.inc │ ├── elf.inc │ └── loader.asm │ ├── kernel │ ├── include │ │ └── config.h │ ├── main.c │ └── start.asm │ └── tests │ └── test.cpp ├── snapshots ├── compile.jpg ├── edit.jpg ├── run.jpg └── single.jpg ├── tutotrial ├── bochsrc └── boot.asm └── x86 ├── app.asm ├── backup ├── app_clock_interrupt.asm ├── app_harddisk_read_write.asm ├── chapter_11.asm └── chapter_12.asm ├── boot.asm ├── build └── bochsrc ├── kernel.asm ├── makefile ├── test.asm └── utils ├── callgate_maker.py └── gdt_maker.py /.gitignore: -------------------------------------------------------------------------------- 1 | x86/build/ 2 | os/build/ 3 | tutotrial/bx_enh_dbg.ini 4 | tutotrial/harddisk.img 5 | tutotrial/harddisk.img.lock 6 | tutotrial/boot.bin 7 | os/src/tests/test 8 | advanced/output 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 汇编语言学习的例子 2 | 3 | 这是汇编语言学习的示例代码,基于王爽 - 《汇编语言》一书,如果你看到了这里,希望它能对你有所帮助。 4 | 5 | 我想你也许和我一样,想要理解计算机的运行原理,那么理解汇编语言这门传说中的语言就必不可少了。 6 | 7 | 下面附上 《汇编语言》中的一段话,大家共勉: 8 | 9 | > 这里再次强调下,我们学习汇编的主要目的,就是通过用汇编语言进行编程而深入地理解计算机底层的基本工作机理,达到可以随心所欲地控制计算机的目的。基于这种考虑,我们的编程活动,大都是直接对硬件进行的。我们希望直接对硬件编程,却并不希望用机器码编程。 10 | 11 | ## 8bit 二进制计算机 12 | 13 | 当然,如果有兴趣的话,可以参考下面我的另一个项目, 14 | 15 | 16 | 17 | 它基于 LogicCircuit 从门电路开始,一步步的实现了一个 8bit 计算机。并且实现了简单的汇编语言,也同样希望对你有所帮助。 18 | 19 | 差不多可以理解为汇编语言描述了怎么使用寄存器,而它表述了寄存器是什么。 20 | 21 | ## emu8086 22 | 23 | 由于 Windows 10 中早就没有了 Debug 工具,于是我找到了 `emu8086` 来模拟 8086 处理器,效果还不错 24 | 25 | 下面附上下载连接 : 26 | 27 | - 用户名:随便输入 28 | - 注册码:27R3VDEFYFX4N0VC3FRTQZX 29 | 30 | 这个软件可以屏蔽操作系统带来的不利因素,也就是模拟出了直接操作硬件的效果,所以不用关注书中关于 DOS 相关的讨论。 31 | 32 | ## 操作方法 33 | 34 | 1. 安装程序,然后输入注册码 35 | 2. 将代码复制到文本框中,注释中文会乱码 36 | 37 | ```asm 38 | ; calculate 2^3 39 | 40 | ASSUME CS:ABC 41 | 42 | ABC SEGMENT 43 | 44 | ; move 2 to register ax 45 | MOV AX,2 46 | ; add ax ax = 4 47 | ADD AX,AX 48 | ; add ax again ax = 8 49 | ADD AX,AX 50 | 51 | ; program return 52 | MOV AX,4C00H 53 | INT 21H ; finish 54 | 55 | ABC ENDS 56 | END 57 | ``` 58 | 59 | ![](./snapshots/edit.jpg) 60 | 61 | 3. 点击 **compile** 进行编译,编译成功后,会提示存储 `bin` 文件。 62 | 63 | ![](./snapshots/compile.jpg) 64 | 65 | 4. 点击 **run** 运行程序。 66 | 67 | ![](./snapshots/run.jpg) 68 | 69 | 5. 运行太快的话,可以使用 **single step** 单步调试,这样就可以看到 寄存器 和 内存的详细变化了。 70 | 71 | ![](./snapshots/single.jpg) 72 | 73 | 6. 祝年轻人万事如意! 74 | 75 | ## 参考资料 76 | 77 | - [王爽 - 《汇编语言》](https://book.douban.com/subject/3037562/) 78 | - [emu8086](http://www.emu8086.com/) 79 | 80 | -------------------------------------------------------------------------------- /advanced/cpuid.s: -------------------------------------------------------------------------------- 1 | #cpuid.s Sample program to extract the processor Vendor ID 2 | 3 | .section .data 4 | output: 5 | .ascii "The processor Vendor ID is xxxxxxxxxxxx\r\n" 6 | 7 | .section .text 8 | 9 | .globl _start 10 | _start: 11 | movl $0, %eax 12 | cpuid 13 | movl $output, %edi 14 | movl %ebx, 28(%edi) 15 | movl %edx, 32(%edi) 16 | movl %ecx, 36(%edi) 17 | movl $4, %eax 18 | movl $1, %ebx 19 | movl $output, %ecx 20 | movl $42, %edx 21 | int $0x80 22 | movl $1, %eax 23 | movl $0, %ebx 24 | int $0x80 25 | -------------------------------------------------------------------------------- /advanced/makefile: -------------------------------------------------------------------------------- 1 | 2 | OUTPUT:= ./output 3 | 4 | define mkdirs 5 | mkdir -p $1 6 | endef 7 | 8 | ASFLAGS:= -gstabs -32 9 | LDFLAGS:= -m elf_i386 10 | 11 | .PHONY:app 12 | app: $(OUTPUT)/cpuid 13 | cp $< $(OUTPUT)/app 14 | 15 | %: %.o 16 | $(call mkdirs,$(dir $@)) 17 | ld $(LDFLAGS) $< -o $@ 18 | 19 | $(OUTPUT)/%.o: %.s 20 | $(call mkdirs,$(dir $@)) 21 | as $(ASFLAGS) $< -o $@ 22 | 23 | .PHONY: clean 24 | clean: 25 | rm -rf $(OUTPUT) 26 | 27 | .PHONY:debug 28 | debug: app 29 | gdb $(OUTPUT)/app 30 | 31 | -------------------------------------------------------------------------------- /assembly.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "python.pythonPath": "~/.envs/test/bin/python" 9 | } 10 | } -------------------------------------------------------------------------------- /language/chapter_04/error_01.asm: -------------------------------------------------------------------------------- 1 | ; 这是一个错误的示例 2 | 3 | aume cs:abc 4 | abc segment 5 | rnov ax,2 6 | add ax,ax 7 | add ax,ax 8 | 9 | end 10 | 11 | -------------------------------------------------------------------------------- /language/chapter_04/experiment_3.asm: -------------------------------------------------------------------------------- 1 | assume cs:codesg 2 | 3 | codesg segment ; 代码段开始 4 | 5 | mov ax,2000H ; 将 2000H 载入 AX 寄存器 6 | mov ss,ax ; 将 AX 中的值 (也就是 刚才的 2000H) 载入栈顶地址寄存器 7 | mov sp,0 ; 将 0 载入 栈偏移地址寄存器,也就是说栈里没数据 8 | add sp,10 ; 将栈顶偏移地址 加 10,栈顶地址变成了 200AH 9 | pop ax ; 将栈顶的 内容弹出载入 AX 寄存器,无论里面是什么,这时栈顶指针 SS + SP 变成了 000CH 10 | pop bx ; 将栈顶的 内容弹出载入 BX 寄存器,无论里面是什么,这时栈顶指针 SS + SP 变成了 000EH 11 | push ax ; 将 AX 中的内容入栈,这时栈顶指针 SS + SP 变成了 000CH 12 | push bx ; 将 BX 中的内容入栈,这时栈顶指针 SS + SP 变成了 000AH 13 | pop ax ; 将栈顶的 内容弹出载入 AX 寄存器,无论里面是什么,这时栈顶指针 SS + SP 变成了 000CH 14 | pop bx ; 将栈顶的 内容弹出载入 BX 寄存器,无论里面是什么,这时栈顶指针 SS + SP 变成了 000EH 15 | 16 | ; 程序返回 17 | mov ax,4c00H 18 | int 21H 19 | 20 | codesg ends ; 代码段结束 21 | end 22 | -------------------------------------------------------------------------------- /language/chapter_04/first_01.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODESG ; 表示 CODESG 是代码段 2 | 3 | CODESG SEGMENT ; 代码段开始 4 | 5 | MOV AX,0123H ; 将 0123H 移动到 AX 寄存器中 6 | MOV BX,0456H ; 将 0456H 移动到 BX 寄存器中 7 | ADD AX,BX ; 将 BX 的值加到 AX 中 8 | ADD AX,AX ; 将 AX 的值加到 AX 中,相当于 AX * 2 9 | 10 | ; 程序返回 11 | MOV AX,4C00H 12 | INT 21H 13 | 14 | CODESG ENDS 15 | 16 | ENDS -------------------------------------------------------------------------------- /language/chapter_04/first_02.asm: -------------------------------------------------------------------------------- 1 | ; calculate 2^3 2 | 3 | ASSUME CS:ABC 4 | 5 | ABC SEGMENT 6 | 7 | ; move 2 to register ax 8 | MOV AX,2 9 | ; add ax ax = 4 10 | ADD AX,AX 11 | ; add ax again ax = 8 12 | ADD AX,AX 13 | 14 | ; program return 15 | MOV AX,4C00H 16 | INT 21H ; finish 17 | 18 | ABC ENDS 19 | END -------------------------------------------------------------------------------- /language/chapter_05/example_1.asm: -------------------------------------------------------------------------------- 1 | MOV AX, 2000H 2 | MOV DS, AX 3 | MOV BX, 1000H 4 | MOV AX,[BX] 5 | INC BX 6 | INC BX 7 | MOV [BX], AX 8 | INC BX 9 | INC BX 10 | MOV [BX], AX 11 | INC BX 12 | MOV [BX], AL 13 | INC BX 14 | MOV [BX], AL 15 | -------------------------------------------------------------------------------- /language/chapter_05/example_5.3.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE 2 | 3 | CODE SEGMENT 4 | 5 | MOV AX, 0FFFFH 6 | MOV DS, AX 7 | MOV BX, 6 8 | MOV AL, [BX] 9 | MOV AH, 0 10 | MOV DX, 0 11 | MOV CX, 3 12 | S: ADD DX, AX 13 | LOOP S 14 | MOV AX, 4C00H 15 | INT 21H 16 | 17 | CODE ENDS 18 | END -------------------------------------------------------------------------------- /language/chapter_05/example_5.7.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE 2 | 3 | CODE SEGMENT 4 | 5 | MOV AX, 0 6 | MOV DS, AX 7 | MOV DS:[26H], AX 8 | 9 | MOV AX,4C00H 10 | INT 21H 11 | 12 | CODE ENDS 13 | 14 | END -------------------------------------------------------------------------------- /language/chapter_05/example_loop.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE 2 | 3 | CODE SEGMENT 4 | 5 | MOV AX,2 6 | MOV CX,11 7 | S: ADD AX,AX 8 | LOOP S 9 | MOV AX, 4c00h 10 | int 21h 11 | CODE ends 12 | end -------------------------------------------------------------------------------- /language/chapter_05/experiment.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE 2 | 3 | CODE SEGMENT 4 | 5 | MOV AX, 100H 6 | MOV DS,AX 7 | MOV AX,0020H 8 | MOV ES, AX 9 | MOV BX, 0 10 | MOV CX, 17H 11 | S: MOV AL, [BX] 12 | MOV ES:[BX], AL 13 | INC BX 14 | LOOP S 15 | 16 | MOV AX, 4C00H 17 | INT 21H 18 | 19 | CODE ENDS 20 | 21 | END -------------------------------------------------------------------------------- /language/chapter_06/example_1.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE 2 | 3 | CODE SEGMENT 4 | 5 | dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h 6 | 7 | MOV BX, 0 8 | MOV AX, 0 9 | MOV CX, 8 10 | 11 | S: ADD AX, CS:[BX] 12 | ADD BX, 2 13 | LOOP S 14 | 15 | MOV AX, 4C00H 16 | INT 21H 17 | 18 | 19 | CODE ENDS 20 | 21 | END -------------------------------------------------------------------------------- /language/chapter_06/example_2.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE 2 | 3 | CODE SEGMENT 4 | 5 | dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h 6 | 7 | START: 8 | MOV BX, 0 9 | MOV AX, 0 10 | MOV CX, 8 11 | 12 | S: ADD AX, CS:[BX] 13 | ADD BX, 2 14 | LOOP S 15 | 16 | MOV AX, 4C00H 17 | INT 21H 18 | 19 | 20 | CODE ENDS 21 | END START 22 | -------------------------------------------------------------------------------- /language/chapter_06/example_3.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE 2 | 3 | CODE SEGMENT 4 | 5 | dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h 6 | 7 | dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 8 | START: 9 | MOV AX, CS 10 | MOV SS, AX 11 | MOV SP, 30H 12 | 13 | MOV BX, 0 14 | MOV CX, 8 15 | 16 | S: PUSH CS:[BX] 17 | ADD BX, 2 18 | LOOP S 19 | 20 | MOV BX, 0 21 | MOV CX, 8 22 | 23 | S0: POP CS:[BX] 24 | ADD BX, 2 25 | LOOP S0 26 | 27 | MOV AX, 4C00H 28 | INT 21H 29 | 30 | 31 | CODE ENDS 32 | END START 33 | -------------------------------------------------------------------------------- /language/chapter_06/example_4.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE, DS:DATA, SS:STACK 2 | 3 | DATA SEGMENT 4 | dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h 5 | DATA ENDS 6 | 7 | STACK SEGMENT: 8 | dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 9 | STACK ENDS 10 | 11 | CODE SEGMENT 12 | 13 | START: 14 | MOV AX, STACK 15 | MOV SS, AX 16 | MOV SP, 20H 17 | 18 | MOV AX, DATA 19 | MOV DS, AX 20 | 21 | MOV BX, 0 22 | MOV CX, 8 23 | 24 | S: PUSH [BX] 25 | ADD BX, 2 26 | LOOP S 27 | 28 | MOV BX, 0 29 | MOV CX, 8 30 | 31 | S0: POP [BX] 32 | ADD BX, 2 33 | LOOP S0 34 | 35 | MOV AX, 4C00H 36 | INT 21H 37 | 38 | CODE ENDS 39 | END START 40 | -------------------------------------------------------------------------------- /language/chapter_06/experiment.asm: -------------------------------------------------------------------------------- 1 | assume cs:code,ds:data,ss:stack 2 | 3 | data segment 4 | dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h 5 | data ends 6 | 7 | stack segment 8 | dw 0,0,0,0,0,0,0,0 9 | stack ends 10 | 11 | code segment 12 | 13 | start: 14 | mov ax,stack 15 | mov ss,ax 16 | mov sp,16 ; = 10h,我的天,研究半天,原来是十进制 17 | 18 | mov ax,data 19 | mov ds,ax 20 | 21 | push ds: [0] 22 | push ds: [2] 23 | pop ds : [2] 24 | pop ds : [0] 25 | 26 | mov ax,4c00h 27 | int 21h 28 | 29 | code ends 30 | end start -------------------------------------------------------------------------------- /language/chapter_07/example_1.asm: -------------------------------------------------------------------------------- 1 | assume cs:code ds:data 2 | 3 | data segment 4 | db 'unIX' 5 | db 'foRK' 6 | data ends 7 | 8 | code segment 9 | 10 | start: 11 | MOV al, 'a' 12 | MOV bl, 'b' 13 | 14 | mov ax, 4c00h 15 | int 21h 16 | code ends 17 | 18 | end start -------------------------------------------------------------------------------- /language/chapter_07/example_2.asm: -------------------------------------------------------------------------------- 1 | ASSUME CS:CODE, DS:DATA 2 | 3 | DATA SEGMENT 4 | DB 'BaSiC' 5 | DB 'iNfOrMaTiOn' 6 | DATA ENDS 7 | 8 | CODE SEGMENT 9 | START: 10 | MOV AX, DATA 11 | MOV DS, AX 12 | 13 | MOV BX, 0 14 | MOV CX, 5 15 | 16 | S: 17 | MOV AL, [BX] 18 | AND AL, 11011111B 19 | MOV [BX], AL 20 | INC BX 21 | LOOP S 22 | 23 | MOV BX, 5 24 | MOV CX, 11 25 | 26 | S0: 27 | MOV AL, [BX] 28 | OR AL, 00100000B 29 | MOV [BX], AL 30 | INC BX 31 | LOOP S0 32 | 33 | MOV AX, 4C00H 34 | INT 21H 35 | 36 | CODE ENDS 37 | 38 | END START 39 | -------------------------------------------------------------------------------- /language/chapter_08/example_1.asm: -------------------------------------------------------------------------------- 1 | ASSUME DS:DATA CS:CODE 2 | 3 | DATA SEGMENT 4 | 5 | DATA ENDS 6 | 7 | 8 | CODE SEGMENT 9 | 10 | START: 11 | 12 | mov ax,DATA 13 | mov ds,ax 14 | 15 | mov bx, 60h 16 | mov word ptr [bx+0ch],38 17 | add word ptr [bx+0eh],70 18 | mov si,0 19 | mov byte ptr [bx+10h+si],'V' 20 | inc SI 21 | mov byte ptr [bx+10h+si],'A' 22 | inc SI 23 | mov byte ptr [bx+10h+si],'X' 24 | 25 | CODE ENDS 26 | 27 | END START -------------------------------------------------------------------------------- /language/chapter_08/experiment.asm: -------------------------------------------------------------------------------- 1 | ASSUME ds:data cs:code 2 | 3 | data segment 4 | db '1975','1976','1977','1978','1979','1980','1981','1982','1983' 5 | db '1984','1985','1986','1987','1988','1989','1990','1991','1992' 6 | db '1993','1994','1995' 7 | 8 | dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 9 | dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000 10 | 11 | dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226 12 | dw 11542, 14430, 15257, 17800 13 | 14 | data ends 15 | 16 | table segment 17 | db 21 dup ('year summ ne ?? ') 18 | table ends 19 | 20 | code segment 21 | start: 22 | mov ax, data 23 | mov es, ax 24 | 25 | mov ax, table 26 | mov ds, ax 27 | 28 | mov bx, 0 ; table row 29 | mov bp, 0 ; year 30 | mov si, 0 ; employee 31 | mov cx, 21 ; loop count 32 | s: 33 | ; mov year 34 | mov ax,es:[bp+0] 35 | mov ds:[bx+0],ax 36 | mov ax,es:[bp+2] 37 | mov ds:[bx+2],ax 38 | 39 | ; mov sum 40 | mov ax,es:[bp+54H] 41 | mov ds:[bx+5],ax 42 | mov ax,es:[bp+56H] 43 | mov ds:[bx+7],ax 44 | 45 | mov ax,es:[si+0A8H] 46 | mov ds:[bx+10],ax 47 | 48 | mov ax,ds:[bx+5] 49 | mov dx,ds:[bx+7] 50 | div word ptr ds:[bx+10] 51 | mov ds:[bx+13],ax 52 | 53 | add si,2 54 | add bp,4 55 | add bx,10h 56 | loop s 57 | 58 | mov ax, 4c00h 59 | int 21h 60 | 61 | code ends 62 | 63 | end start -------------------------------------------------------------------------------- /language/chapter_09/exam_1.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | dw 0, 0, 0 5 | data ends 6 | 7 | code segment 8 | start: 9 | 10 | mov ax, data 11 | mov ds, ax 12 | mov bx, 0 13 | jmp word ptr [bx + 1] 14 | 15 | code ends 16 | end start 17 | 18 | -------------------------------------------------------------------------------- /language/chapter_09/example_01.asm: -------------------------------------------------------------------------------- 1 | ASSUME cs:code 2 | 3 | code segment 4 | 5 | start: 6 | mov ax, offset start 7 | s: 8 | mov ax, offset s 9 | 10 | code ends 11 | end start -------------------------------------------------------------------------------- /language/chapter_09/example_02.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | s: 5 | mov ax, bx 6 | mov si, offset s 7 | mov di, offset s0 8 | mov ax, cs:[si] 9 | mov cs:[di], ax 10 | s0: 11 | nop 12 | nop 13 | 14 | code ends 15 | end s -------------------------------------------------------------------------------- /language/chapter_09/example_03.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | mov ax, 0 7 | jmp short s 8 | add ax, 1 9 | s: 10 | inc ax 11 | 12 | code ends 13 | end start -------------------------------------------------------------------------------- /language/chapter_09/example_04.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | mov ax, 0 7 | mov bx, 0 8 | jmp short s 9 | add ax, 1 10 | s: 11 | inc ax 12 | 13 | code ends 14 | 15 | end start -------------------------------------------------------------------------------- /language/chapter_09/example_05.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | mov ax,0 8 | mov bx, 0 9 | jmp far ptr s 10 | db 256 dup (0) 11 | 12 | s: 13 | add ax, 1 14 | inc ax 15 | 16 | code ends 17 | 18 | end start -------------------------------------------------------------------------------- /language/chapter_09/experiment_1.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | mov ax, 4c00h 6 | int 21h 7 | 8 | start: 9 | mov ax, 0 10 | s: 11 | nop 12 | nop 13 | 14 | mov di, offset s 15 | mov si, offset s2 16 | mov ax, cs:[si] 17 | mov cs:[di], ax 18 | 19 | s0: 20 | jmp short s 21 | 22 | s1: 23 | mov ax, 0 24 | int 21h 25 | 26 | s2: 27 | jmp short s1 28 | nop 29 | 30 | code ends 31 | end start -------------------------------------------------------------------------------- /language/chapter_09/experiment_2.asm: -------------------------------------------------------------------------------- 1 | name "experiment_2" 2 | 3 | assume cs:code ds:data 4 | 5 | data segment 6 | db 'Welcome to asm!' ; 15 7 | data ends 8 | 9 | code segment 10 | 11 | start: 12 | mov ax, 0b800H; 13 | mov es, ax 14 | mov ax, data 15 | mov ds, ax 16 | mov dx, 4 ; loop 3 lines 17 | mov bx, 1822; show in middle 1760(row) + 62 (column) 18 | line: 19 | mov cx, 15 20 | mov di, 0 21 | char: 22 | mov al, ds:[di] 23 | mov es:[bx], al 24 | inc di 25 | inc bx 26 | 27 | ; 01000010B = red - green 28 | ; 00000010B = black - green 29 | ; 11000010B = blink - red - green 30 | ; 01001010B = high - red - green 31 | ; 00000111B = black - white; 32 | ; 01110001B = white - blue; 33 | mov es:[bx], 11000010B ; 34 | inc bx 35 | loop char 36 | 37 | sub dx, 1 38 | mov cx, dx 39 | 40 | mov ax, bx 41 | add ax, 160 42 | sub ax, 30 43 | mov bx, ax 44 | loop line 45 | 46 | code ends 47 | end start -------------------------------------------------------------------------------- /language/chapter_10/exam_01.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | stack segment 4 | 5 | db 16 dup (0) 6 | 7 | stack ends 8 | 9 | code segment 10 | start: 11 | mov ax, stack 12 | mov ss, ax 13 | mov sp, 16 14 | 15 | mov ax, 1000h 16 | push ax 17 | mov ax, 0000h 18 | push ax 19 | retf 20 | 21 | code ends 22 | 23 | end start 24 | -------------------------------------------------------------------------------- /language/chapter_10/exam_05.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | stack segment 4 | dw 8 dup (0) 5 | stack ends 6 | 7 | code segment 8 | 9 | start: 10 | mov ax, stack 11 | mov sp, 16 12 | mov ds, ax 13 | mov ax, 0 14 | call word ptr ds:[0eh] 15 | inc ax 16 | inc ax 17 | inc ax 18 | mov ax 4c00h 19 | int 21h 20 | 21 | code ends 22 | end start -------------------------------------------------------------------------------- /language/chapter_10/example_01.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | stack segment 4 | 5 | db 16 dup (0) 6 | 7 | stack ends 8 | 9 | code segment 10 | mov ax, 4c00h 11 | int 21h 12 | 13 | start: 14 | mov ax, stack 15 | mov ss, ax 16 | mov sp, 16 17 | mov ax, 0 18 | push ax 19 | mov bx, 0 20 | ret 21 | 22 | code ends 23 | 24 | end start 25 | -------------------------------------------------------------------------------- /language/chapter_10/example_02.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | stack segment 4 | 5 | db 16 dup (0) 6 | 7 | stack ends 8 | 9 | code segment 10 | mov ax, 4c00h 11 | int 21h 12 | 13 | start: 14 | mov ax, stack 15 | mov ss, ax 16 | mov sp, 16 17 | mov ax, 0 18 | push cs 19 | push ax 20 | mov bx, 0 21 | retf 22 | 23 | code ends 24 | 25 | end start 26 | -------------------------------------------------------------------------------- /language/chapter_10/example_03.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | mov ax, 1 8 | mov cx, 3 9 | call s 10 | mov bx, ax 11 | 12 | mov ax, 4c00h 13 | int 21h 14 | s: 15 | add ax, ax 16 | loop s 17 | ret 18 | 19 | code ends 20 | end start -------------------------------------------------------------------------------- /language/chapter_10/example_04.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | dw 1, 2, 3, 4, 5, 6, 7, 8 6 | dd 0, 0, 0, 0, 0, 0, 0, 0 7 | 8 | data ends 9 | 10 | 11 | code segment 12 | 13 | cube: 14 | mov ax, bx 15 | mul bx 16 | mul bx 17 | ret 18 | 19 | start: 20 | 21 | mov ax, data 22 | mov ds, ax 23 | mov si, 0 24 | mov di, 16 25 | 26 | mov cx, 8 27 | s: 28 | mov bx, [si] 29 | call cube 30 | 31 | mov [di], ax 32 | mov [di + 2], dx 33 | 34 | add si, 2 35 | add di, 4 36 | loop s 37 | 38 | mov ax, 4c00h 39 | int 21h 40 | 41 | 42 | code ends 43 | end start -------------------------------------------------------------------------------- /language/chapter_10/example_05.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | dw 'conversation' 6 | 7 | data ends 8 | 9 | 10 | code segment 11 | 12 | start: 13 | 14 | mov ax, data 15 | mov ds, ax 16 | mov si, 0 17 | mov cx, 12 18 | 19 | call capital 20 | 21 | call finish 22 | 23 | capital: 24 | 25 | and byte ptr [si], 11011111b 26 | inc si 27 | loop capital 28 | ret 29 | 30 | finish: 31 | mov ax, 4c00h 32 | int 21h 33 | 34 | code ends 35 | end start -------------------------------------------------------------------------------- /language/chapter_10/example_06.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | dw 'conversation', 0 6 | 7 | data ends 8 | 9 | 10 | code segment 11 | 12 | start: 13 | 14 | mov ax, data 15 | mov ds, ax 16 | mov si, 0 17 | 18 | call capital 19 | 20 | call finish 21 | 22 | capital: 23 | mov cl, [si] 24 | mov ch, 0 25 | jcxz ok 26 | and byte ptr [si], 11011111b 27 | inc si 28 | jmp short capital 29 | ok: 30 | ret 31 | 32 | finish: 33 | mov ax, 4c00h 34 | int 21h 35 | 36 | code ends 37 | end start -------------------------------------------------------------------------------- /language/chapter_10/example_07.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | db 'conversation', 0 6 | db 'unix', 0 7 | db 'windpipe', 0 8 | db 'goodgoodstudy', 0 9 | 10 | data ends 11 | 12 | 13 | code segment 14 | 15 | start: 16 | 17 | mov ax, data 18 | mov ds, ax 19 | mov bx, 0 20 | 21 | mov cx, 4 22 | mov si, 0 23 | s: 24 | call capital 25 | loop s 26 | 27 | call finish 28 | 29 | capital: 30 | push cx 31 | 32 | change: 33 | mov cl, [si] 34 | mov ch, 0 35 | jcxz ok 36 | and byte ptr [si], 11011111b 37 | inc si 38 | jmp short change 39 | ok: 40 | inc si 41 | pop cx 42 | ret 43 | 44 | finish: 45 | mov ax, 4c00h 46 | int 21h 47 | 48 | code ends 49 | end start -------------------------------------------------------------------------------- /language/chapter_10/experiment_01.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | db 'Welcome to asm!', 0 6 | 7 | data ends 8 | 9 | 10 | code segment 11 | 12 | start: 13 | mov dh, 8 14 | mov dl, 3 15 | mov cl, 2 16 | 17 | mov ax, data 18 | mov ds, ax 19 | mov si, 0 20 | 21 | call show_str 22 | 23 | call finish 24 | 25 | show_str: 26 | 27 | mov al, dh 28 | mov bl, 160 ; line number 29 | mul bl; row 30 | 31 | mov dh, 0 32 | add ax, dx; column 33 | add ax, dx; * 2 34 | mov bx, ax ; mov start location 35 | 36 | mov ax, 0b800H; 37 | mov es, ax 38 | 39 | mov ax, data 40 | mov ds, ax 41 | 42 | mov dl, cl 43 | mov di, 0 44 | 45 | char: 46 | mov cl, ds:[di] 47 | mov ch, 0 48 | jcxz ok 49 | 50 | mov al, ds:[di] 51 | mov es:[bx], al 52 | inc di 53 | inc bx 54 | mov es:[bx], dl ; 55 | inc bx 56 | jmp short char 57 | 58 | ok: 59 | ret 60 | 61 | finish: 62 | mov ax, 4c00h 63 | int 21h 64 | 65 | code ends 66 | end start -------------------------------------------------------------------------------- /language/chapter_11/example_01.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | ; test ZF 8 | mov ax, 1 9 | sub ax, 1 10 | 11 | mov ax, 2 12 | sub ax, 1 13 | 14 | ; test PF 15 | mov al, 1 16 | add al, 10 17 | 18 | mov al, 1 19 | or al, 2 20 | 21 | ; test SF 22 | 23 | mov al, 10000001B 24 | add al, 1 25 | 26 | mov al, 10000001B 27 | add al, 01111111B 28 | 29 | ; test CF 30 | 31 | mov al, 98h 32 | add al, al 33 | 34 | jmp short finish 35 | 36 | finish: 37 | 38 | mov ax, 4c00h 39 | int 21h 40 | 41 | code ends 42 | 43 | end start -------------------------------------------------------------------------------- /language/chapter_11/example_02.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | ; test cmp 8 | 9 | mov ax, 8 10 | mov bx, 3 11 | cmp ax, bx 12 | 13 | jmp short finish 14 | 15 | finish: 16 | 17 | mov ax, 4c00h 18 | int 21h 19 | 20 | code ends 21 | 22 | end start -------------------------------------------------------------------------------- /language/chapter_11/example_03.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | db 8, 11, 8, 1, 8, 5, 63, 38 6 | 7 | data ends 8 | 9 | code segment 10 | 11 | start: 12 | 13 | mov ax, data 14 | mov ds, ax 15 | mov bx, 0 16 | mov ax, 0 17 | mov cx, 8 18 | 19 | s: 20 | cmp byte ptr [bx], 8 21 | jne next 22 | inc ax 23 | 24 | next: 25 | 26 | inc bx 27 | loop s 28 | 29 | jmp short finish 30 | 31 | finish: 32 | 33 | mov ax, 4c00h 34 | int 21h 35 | 36 | code ends 37 | 38 | end start -------------------------------------------------------------------------------- /language/chapter_11/example_04.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | db 'Welcome to masm!' 6 | db 16 dup (0) 7 | 8 | data ends 9 | 10 | code segment 11 | 12 | start: 13 | 14 | mov ax, data 15 | mov ds, ax 16 | 17 | mov si, 0 18 | mov es, ax 19 | mov di, 16 20 | mov cx, 16 21 | 22 | cld 23 | 24 | rep movsb 25 | 26 | code ends 27 | 28 | end start -------------------------------------------------------------------------------- /language/chapter_11/example_05.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | data ends 6 | 7 | code segment 8 | 9 | start: 10 | 11 | mov ax, 0 12 | push ax 13 | popf 14 | mov ax, 0fff0h 15 | add ax, 0010h 16 | pushf 17 | pop ax 18 | and al, 11000101B 19 | and al, 00001000B 20 | 21 | code ends 22 | 23 | end start -------------------------------------------------------------------------------- /language/chapter_11/experiment_11.asm: -------------------------------------------------------------------------------- 1 | name 'letterc' 2 | 3 | assume cs:code 4 | 5 | data segment 6 | 7 | db "Beginner's All-purpose Symbolic Instruction Code.",0 8 | 9 | data ends 10 | 11 | code segment 12 | 13 | start: 14 | 15 | mov ax, data 16 | mov ds, ax 17 | 18 | mov si, 0 19 | 20 | call letterc 21 | 22 | call finish 23 | 24 | letterc: 25 | 26 | mov al, [si] 27 | cmp al, 0 28 | je finish 29 | cmp al, 'a' 30 | jb next 31 | cmp al, 'z' 32 | ja next 33 | 34 | ;and al, 11011111B 35 | ;mov [si], al 36 | 37 | and [si], 11011111B 38 | 39 | next: 40 | inc si 41 | jmp short letterc 42 | 43 | 44 | finish: 45 | 46 | mov ax, 4c00h 47 | int 21h 48 | 49 | code ends 50 | 51 | end start -------------------------------------------------------------------------------- /language/chapter_12/example_01.asm: -------------------------------------------------------------------------------- 1 | 2 | ; 1. get interrupt code N 3 | ; 2. pushf 4 | ; 3. TF = 0, IF = 0 5 | ; 4. push CS 6 | ; 5. push IP 7 | ; 6. (IP)=(N *4), (CS)=(N*4+2) 8 | 9 | assume cs:code 10 | 11 | code segment 12 | 13 | start: 14 | mov ax, 1000h 15 | mov bh, 1 16 | div bh 17 | 18 | call finish 19 | 20 | finish: 21 | 22 | mov ax, 4c00h 23 | int 21h 24 | 25 | code ends 26 | 27 | end start -------------------------------------------------------------------------------- /language/chapter_12/example_02.asm: -------------------------------------------------------------------------------- 1 | 2 | ; 1. get interrupt code N 3 | ; 2. pushf 4 | ; 3. TF = 0, IF = 0 5 | ; 4. push CS 6 | ; 5. push IP 7 | ; 6. (IP)=(N *4), (CS)=(N*4+2) 8 | 9 | assume cs:code 10 | 11 | code segment 12 | 13 | start: 14 | 15 | install: 16 | mov ax, cs 17 | mov ds, ax 18 | mov si, offset show_error 19 | 20 | mov ax, 0 21 | mov es, ax 22 | mov di, 200h 23 | 24 | mov cx, offset show_error_end - offset show_error 25 | 26 | cld; positive direction 27 | ; std; negative direction 28 | 29 | rep movsb 30 | 31 | mov ax, 0 32 | mov es, ax 33 | mov word ptr es:[0*4], 200h 34 | mov word ptr es:[0*4+2], 0 35 | 36 | mov ax, 1000h 37 | mov bh, 1 38 | div bh 39 | 40 | mov ax, 4c00h 41 | int 21h 42 | 43 | show_error: 44 | jmp short show_error_start 45 | show_error_data: 46 | db 'Overflow!', 0 47 | show_error_start: 48 | 49 | mov ax, cs 50 | mov ds, ax 51 | mov si, 200h + offset show_error_data - offset show_error 52 | 53 | mov ax, 0b800h 54 | mov es, ax 55 | mov di, 12*160 + 36 * 2 56 | 57 | char: 58 | mov cl, ds:[si] 59 | cmp cl, 0 60 | je short show_error_ret 61 | 62 | mov al, ds:[si] 63 | mov es:[di], al 64 | inc si 65 | add di, 2 66 | jmp short char 67 | 68 | show_error_ret: 69 | mov ax, 4c00h 70 | int 21h 71 | 72 | show_error_end: 73 | 74 | 75 | code ends 76 | 77 | end start -------------------------------------------------------------------------------- /language/chapter_13/example_01.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | mov ax, 0b800h 7 | mov es, ax 8 | mov byte ptr es:[12*160 + 40 * 2], ',' 9 | int 0 10 | 11 | code ends 12 | end start -------------------------------------------------------------------------------- /language/chapter_13/example_02.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | mov ax, 3456 7 | int 7ch 8 | add ax, ax 9 | adc dx, dx 10 | mov ax, 4c00h 11 | int 21h 12 | 13 | code ends 14 | 15 | end start -------------------------------------------------------------------------------- /language/chapter_13/example_02_install.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | mov ax, cs 8 | mov ds, ax 9 | mov si, offset sqr 10 | mov ax, 0 11 | mov es, ax 12 | mov di, 200h 13 | mov cx, offset sqrend-offset sqr 14 | 15 | cld 16 | rep movsb 17 | 18 | mov ax, 0 19 | mov es, ax 20 | mov word ptr es:[7ch * 4], 200h 21 | mov word ptr es:[7ch * 4 + 2], 0 22 | 23 | mov ax, 4c00h 24 | int 21h 25 | 26 | sqr: 27 | mul ax 28 | iret 29 | 30 | sqrend: 31 | nop 32 | 33 | code ends 34 | 35 | end start -------------------------------------------------------------------------------- /language/chapter_13/example_03.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | db 'conversation', 0 6 | 7 | data ends 8 | 9 | code segment 10 | 11 | start: 12 | 13 | mov ax, data 14 | mov ds, ax 15 | mov si, 0 16 | 17 | int 7ch 18 | mov ax, 4c00h 19 | int 21h 20 | 21 | code ends 22 | 23 | end start -------------------------------------------------------------------------------- /language/chapter_13/example_03_install.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | mov ax, cs 8 | mov ds, ax 9 | mov si, offset capital 10 | 11 | mov ax, 0 12 | mov es, ax 13 | mov di, 200h 14 | mov cx, offset capital_end - offset capital 15 | 16 | cld 17 | rep movsb 18 | 19 | mov ax, 0 20 | mov es, ax 21 | mov word ptr es:[7ch * 4], 200h 22 | mov word ptr es:[7ch * 4 + 2], 0 23 | mov ax, 4c00h 24 | int 21h 25 | 26 | capital: 27 | 28 | push cx 29 | push si 30 | 31 | change: 32 | mov cl, [si] 33 | mov ch, 0 34 | jcxz ok 35 | 36 | and byte ptr [si], 11011111b 37 | inc si 38 | jmp short change 39 | 40 | ok: 41 | pop si 42 | pop cx 43 | iret 44 | 45 | capital_end: nop 46 | 47 | code ends 48 | 49 | end start -------------------------------------------------------------------------------- /language/chapter_13/example_bios.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | mov ah, 2 ; set cursor 8 | mov bh, 0 ; page 0 9 | mov dh, 5 ; line 5 10 | mov dl, 12; column 12 11 | int 10h 12 | 13 | mov ah, 9 14 | mov al, 'a' 15 | mov bl, 11001010b; color 16 | mov bh, 0 17 | mov cx, 3 18 | int 10h 19 | 20 | mov ax, 4c00h 21 | int 21h 22 | 23 | code ends 24 | 25 | end start -------------------------------------------------------------------------------- /language/chapter_13/example_dos.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | db 'Welcome to masm!', '$' 6 | 7 | data ends 8 | 9 | code segment 10 | 11 | start: 12 | 13 | mov ah, 2 ; set cursor 14 | mov bh, 0 ; page 0 15 | mov dh, 5 ; line 5 16 | mov dl, 12; column 12 17 | int 10h 18 | 19 | mov ax, data 20 | mov ds, ax 21 | mov dx, 0 22 | 23 | mov ah, 9 24 | int 21h 25 | 26 | mov ax, 4c00h 27 | int 21h 28 | 29 | code ends 30 | 31 | end start -------------------------------------------------------------------------------- /language/chapter_13/experiment_1.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | data segment 4 | 5 | db 'Welcome to masm!', 0 6 | 7 | data ends 8 | 9 | code segment 10 | 11 | start: 12 | 13 | mov dh, 10 14 | mov dl, 10 15 | mov cl, 2 16 | mov ax, data 17 | mov ds, ax 18 | mov si, 0 19 | int 7ch 20 | 21 | mov ax, 4c00h 22 | int 21h 23 | 24 | code ends 25 | 26 | end start -------------------------------------------------------------------------------- /language/chapter_13/experiment_1_install.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | mov ax, cs 8 | mov ds, ax 9 | mov si, offset process 10 | 11 | mov ax, 0 12 | mov es, ax 13 | mov di, 200h 14 | mov cx, offset process_end - offset process 15 | 16 | cld 17 | rep movsb 18 | 19 | mov ax, 0 20 | mov es, ax 21 | mov word ptr es:[7ch * 4], 200h 22 | mov word ptr es:[7ch * 4 + 2], 0 23 | mov ax, 4c00h 24 | int 21h 25 | 26 | process: 27 | mov al, dh 28 | mov bl, 160 ; line number 29 | mul bl; row 30 | 31 | mov dh, 0 32 | add ax, dx; column 33 | add ax, dx; * 2 34 | mov bx, ax ; mov start location 35 | 36 | mov ax, 0b800H; 37 | mov es, ax 38 | 39 | mov dl, cl 40 | mov di, 0 41 | 42 | char: 43 | mov cl, ds:[di] 44 | mov ch, 0 45 | jcxz ok 46 | 47 | mov al, ds:[di] 48 | mov es:[bx], al 49 | inc di 50 | inc bx 51 | mov es:[bx], dl ; 52 | inc bx 53 | jmp short char 54 | 55 | ok: 56 | iret 57 | 58 | process_end: nop 59 | 60 | code ends 61 | 62 | end start -------------------------------------------------------------------------------- /language/chapter_14/example_01.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | mov al, 8 8 | out 70h, al 9 | in al, 71h 10 | 11 | mov ah, al 12 | mov cl, 4 13 | shr ah, cl 14 | and al, 00001111b 15 | 16 | add ah, 30h 17 | add al, 30h 18 | 19 | mov bx, 0b800h 20 | mov es, bx 21 | mov byte ptr es:[160*12 + 40 * 2], ah 22 | mov byte ptr es:[160*12 + 40 * 2 + 2], ah 23 | 24 | mov ax, 4c00h 25 | int 21h 26 | 27 | code ends 28 | 29 | end start -------------------------------------------------------------------------------- /language/chapter_15/example_01.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | code segment 4 | 5 | start: 6 | 7 | mov ax, 0b800h 8 | mov es, ax 9 | 10 | mova: 11 | mov ah, 'a' 12 | s: 13 | mov es:[160 * 12 + 40 * 2], ah 14 | inc ah 15 | cmp ah, 'z' 16 | je mova 17 | jmp short s 18 | 19 | mov ax, 4c00h 20 | int 21h 21 | 22 | code ends 23 | 24 | end start -------------------------------------------------------------------------------- /language/chapter_15/example_02.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | stack segment 4 | db 128 dup (0) 5 | stack ends 6 | 7 | code segment 8 | 9 | start: 10 | 11 | mov ax, stack 12 | mov ss, ax 13 | mov sp, 128 14 | 15 | mov ax, 0b800h 16 | mov es, ax 17 | mov ah, 'a' 18 | s: 19 | mov es:[160 * 12 + 40 * 2], ah 20 | call delay 21 | inc ah 22 | cmp ah, 'z' 23 | jna s 24 | 25 | mov ax, 4c00h 26 | int 21h 27 | 28 | delay: 29 | push ax 30 | push dx 31 | mov dx, 1000h 32 | mov ax, 0 33 | s1: 34 | sub ax, 1 35 | sbb dx, 0 36 | cmp ax, 0 37 | jne s1 38 | 39 | cmp dx, 0 40 | jne s1 41 | 42 | pop dx 43 | pop ax 44 | ret 45 | 46 | 47 | code ends 48 | 49 | end start -------------------------------------------------------------------------------- /language/chapter_15/example_03.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | stack segment 4 | 5 | db 128 dup (0) 6 | 7 | stack ends 8 | 9 | 10 | data segment 11 | dw 0, 0 12 | data ends 13 | 14 | code segment 15 | 16 | start: 17 | 18 | mov ax, stack 19 | mov ss, ax 20 | mov sp, 128 21 | 22 | mov ax, data 23 | mov ds, ax 24 | 25 | push es:[9*4] 26 | pop ds:[0] 27 | push es:[9*4 + 2] 28 | pop ds:[2] 29 | 30 | mov word ptr es:[9 * 4], offset int9 31 | mov es:[9 * 4 + 2], cs 32 | 33 | mov ax, 0b800h 34 | mov es, ax 35 | mov ah, 'a' 36 | s: 37 | mov es:[160 * 12 + 40 * 2], ah 38 | inc ah 39 | cmp ah, 'z' 40 | jna s 41 | 42 | mov ax, 0 43 | mov es, ax 44 | 45 | push ds:[0] 46 | pop es:[9 * 4] 47 | push ds:[2] 48 | pop es:[9 * 4 + 2] 49 | 50 | mov ax, 4c00h 51 | int 21h 52 | 53 | int9: 54 | push ax 55 | push bx 56 | push es 57 | 58 | in al, 60h 59 | 60 | pushf 61 | pushf 62 | pop bx 63 | and bh, 11111100b 64 | push bx 65 | popf 66 | call dword ptr ds:[0] 67 | 68 | cmp al, 1 69 | jne int9ret 70 | 71 | mov ax, 0b800h 72 | mov es, ax 73 | inc byte ptr es:[160 * 12 + 40 * 2 + 1] 74 | 75 | int9ret: 76 | pop es 77 | pop bx 78 | pop ax 79 | iret 80 | 81 | 82 | code ends 83 | 84 | end start -------------------------------------------------------------------------------- /language/chapter_15/example_int9.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | stack segment 4 | 5 | db 128 dup (0) 6 | 7 | stack ends 8 | 9 | 10 | data segment 11 | dw 0, 0 12 | data ends 13 | 14 | code segment 15 | 16 | start: 17 | 18 | mov ax, stack 19 | mov ss, ax 20 | mov sp, 128 21 | 22 | mov ax, data 23 | mov ds, ax 24 | 25 | push es:[9*4] 26 | pop ds:[0] 27 | push es:[9*4 + 2] 28 | pop ds:[2] 29 | 30 | mov word ptr es:[9 * 4], offset int9 31 | mov es:[9 * 4 + 2], cs 32 | 33 | mov ax, 0b800h 34 | mov es, ax 35 | mov ah, 'a' 36 | s: 37 | mov es:[160 * 12 + 40 * 2], ah 38 | inc ah 39 | cmp ah, 'z' 40 | jna s 41 | 42 | mov ax, 0 43 | mov es, ax 44 | 45 | push ds:[0] 46 | pop es:[9 * 4] 47 | push ds:[2] 48 | pop es:[9 * 4 + 2] 49 | 50 | mov ax, 4c00h 51 | int 21h 52 | 53 | int9: 54 | push ax 55 | push bx 56 | push es 57 | 58 | in al, 60h 59 | 60 | pushf 61 | pushf 62 | pop bx 63 | and bh, 11111100b 64 | push bx 65 | popf 66 | call dword ptr ds:[0] 67 | 68 | cmp al, 1 69 | jne int9ret 70 | 71 | mov ax, 0b800h 72 | mov es, ax 73 | inc byte ptr es:[160 * 12 + 40 * 2 + 1] 74 | 75 | int9ret: 76 | pop es 77 | pop bx 78 | pop ax 79 | iret 80 | 81 | 82 | code ends 83 | 84 | end start -------------------------------------------------------------------------------- /language/chapter_15/example_int9_install.asm: -------------------------------------------------------------------------------- 1 | assume cs:code 2 | 3 | stack segment 4 | db 128 dup (0) 5 | stack ends 6 | 7 | code segment 8 | 9 | start: 10 | mov ax,stack 11 | mov ss,ax 12 | mov sp,128 13 | 14 | push cs 15 | pop ds 16 | 17 | mov ax,0 18 | mov es,ax 19 | mov si, offset int9 ; 设置ds:si指向源地址 20 | mov di, 204h ; 设置es:di指向目的地址 21 | mov cx,offset int9end-offset int9 ; 设置ex为传输长度 22 | cld ; 设置传输方向为正 23 | 24 | rep movsb 25 | 26 | push es: [9*4] 27 | pop es: [200h] 28 | push es: [9*4+2] 29 | pop es: [202h] 30 | 31 | cli 32 | mov word ptr es: [9*4],204h 33 | mov word ptr es: [9*4+2],0 34 | sti 35 | 36 | mov ax,4c00h 37 | int 21h 38 | 39 | int9: 40 | push ax 41 | push bx 42 | push cx 43 | push es 44 | 45 | in al,60h 46 | 47 | pushf 48 | call dword ptr cs: [200h] 49 | 50 | cmp al,3bh 51 | jne int9ret 52 | 53 | mov ax,0b800h 54 | mov es,ax 55 | mov bx,1 56 | mov cx,2000 57 | 58 | s: 59 | inc byte ptr es:[bx] 60 | add bx,2 61 | loop s 62 | 63 | int9ret: 64 | pop es 65 | pop cx 66 | pop bx 67 | pop ax 68 | iret 69 | 70 | int9end: 71 | nop 72 | 73 | code ends 74 | end start -------------------------------------------------------------------------------- /language/chapter_15/experiment_01.asm: -------------------------------------------------------------------------------- 1 | 2 | assume cs : code, ss : stack 3 | 4 | stack SEGMENT 5 | dw 64 dup (0) 6 | stack ENDS 7 | 8 | code SEGMENT 9 | 10 | start: ;改变中断向量到本程序中的中断例程处 11 | mov ax, 0 12 | mov es, ax 13 | mov ax, stack 14 | mov ss, ax 15 | mov sp, 64 16 | mov ds, ax 17 | 18 | ;分别将中断程序cs:ip入栈ds:[si]分别存ip,cs 19 | push es : [9 * 4 + 2] 20 | push es : [9 * 4] 21 | mov si, sp 22 | 23 | ;改变中断向量 24 | cli 25 | mov ax, code 26 | mov es : [9 * 4 + 2], ax 27 | mov word ptr es : [9 * 4], offset int9 28 | sti 29 | 30 | mov ax, 0b800h 31 | mov es, ax 32 | mov bl, 'A' 33 | print: mov es : [12 * 160 + 36 * 2], bl 34 | add bl, 1 35 | call delay 36 | cmp bl, 'Z' 37 | jna print 38 | 39 | ;改回中断向量 40 | mov ax, 0 41 | mov es, ax 42 | cli 43 | mov ax, word ptr ds : [si + 2] 44 | mov es : [9 * 4 + 2], ax 45 | mov ax, word ptr ds : [si] 46 | mov es : [9 * 4], ax 47 | sti 48 | 49 | mov ax, 4c00h 50 | int 21h 51 | 52 | 53 | delay: push ax 54 | push bx 55 | mov ax, 0 56 | mov bx, 1000h 57 | wl: 58 | sub ax, 1 59 | sbb bx, 0 60 | cmp ax, 0 61 | jne wl 62 | cmp bx, 0 63 | jne wl 64 | pop bx 65 | pop ax 66 | ret 67 | 68 | ;原来的中断例程存放在ds:[si]处 69 | int9: 70 | push ax 71 | push es 72 | pushf ;中断例程最后是iret 73 | 74 | ;注意是dword 75 | call dword ptr ds : [si] ;运行原中断例程处理硬件细节 76 | 77 | in al, 60h 78 | cmp al, 1 79 | jne int9end 80 | 81 | mov ax, 0b800h 82 | mov es, ax 83 | add byte ptr es : [12 * 160 + 36 * 2 + 1], 1 84 | 85 | int9end: 86 | pop es 87 | pop ax 88 | iret 89 | 90 | code ends 91 | end start 92 | 93 | -------------------------------------------------------------------------------- /note/8086 CPU 相关寄存器.md: -------------------------------------------------------------------------------- 1 | # 8086 CPU 相关寄存器 2 | 3 | [annotation]: (2939c4a5-15db-4636-9d3e-cf58fc5d17e9) 4 | [annotation]: (public) 5 | [annotation]: (2020-07-01 19:03:26) 6 | [annotation]: (计算机技术) 7 | [annotation]: (汇编语言|8086) 8 | [annotation]: (false) 9 | [annotation]: (http://blog.ccyg.studio/article/2939c4a5-15db-4636-9d3e-cf58fc5d17e9) 10 | 11 | - AX - 累加器 12 | - AH - 高位 13 | - AL - 低位 14 | - BX - 基址寄存器 15 | - BH - 高位 16 | - BL - 低位 17 | - CX - 计数寄存器 18 | - CH - 高位 19 | - CL - 低位 20 | - DX - 数据寄存器 21 | - DH - 高位 22 | - DL - 低位 23 | - CS - 代码段寄存器 24 | - DS - 数据段寄存器 25 | - ES - 附加数据段寄存器 26 | - SS - 栈段寄存器 27 | - SP - 栈顶指针寄存器 28 | - SI - 源变址寄存器 29 | - DI - 目的变址寄存器 30 | - IP - 指令指针寄存器 31 | - FLAG - 标志寄存器 32 | - CF - 进位标志位 - 第 0 位 33 | - PF - 奇偶标志位 - 第 2 位 34 | - AF - 辅助进位标志位 - 第 4 位 35 | - ZF - 零标志位 - 第 6 位 36 | - SF - 符号标志位 - 第 7 位 37 | - TF - 追踪标志位 - 第 8 位 38 | - IF - 中断允许标志位 - 第 9 位 39 | - DF - 方向标志位 - 第 10 位 40 | - OF - 溢出标志位 - 第 11 位 41 | 42 | 43 | 44 | ## 注意事项 45 | 46 | - 在串处理指令中,**SI** 用作隐含的源串地址,默认在 **DS** 中;**DI** 用做隐含的目的串地址,默认在 **ES** 中;此时不能混用。 -------------------------------------------------------------------------------- /note/8086 数据类型.md: -------------------------------------------------------------------------------- 1 | # 8086 数据类型 2 | 3 | [annotation]: (c9f1adca-ce19-428f-bd96-8b58369b18f9) 4 | [annotation]: (public) 5 | [annotation]: (2020-07-02 21:00:23) 6 | [annotation]: (计算机技术) 7 | [annotation]: (汇编语言) 8 | [annotation]: (false) 9 | [annotation]: (http://blog.ccyg.studio/article/c9f1adca-ce19-428f-bd96-8b58369b18f9) 10 | 11 | - DB:Define Byte,定义字节(8位/1字节)无符号整数;等同于BYTE; 12 | - DW:Define Word,定义字(16位/2字节)无符号整数;等同于WORD; 13 | - DD:Define DoubleWord,定义双字(32位/4字节)无符号整数;等同于DWORD; 14 | - DF:Defined Farword,定义三字(48位/6字节)无符号整数;等同于FWORD; 15 | - DQ:Define QuadWord,定义四字(64位/8字节)无符号整数;等同于QWORD; 16 | - DT:Define TenBytes,定义五字(80位/10字节)无符号整数;等同于TBYTE; 17 | - BYTE : 8位无符号整数 18 | - WORD : 16位无符号整数 19 | - DWORD : 32位无符号整数 20 | - QWORD : 64位整数 21 | - TBYTE : 80位整数 22 | - SBYTE : 8位有符号整数 23 | - SWORD : 16位有符号整数 24 | - SDWORD: 32位有符号整数 25 | - FWORD : 48位整数(保护模式下作远指针) 26 | - REAL4 : 32位IEEE短实数 27 | - REAL8 : 64位IEEE长实数 28 | - REAL10: 80位IEEE扩展精度实数 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /os/bochsrc: -------------------------------------------------------------------------------- 1 | # configuration file generated by Bochs 2 | plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, iodebug=true 3 | config_interface: textconfig 4 | display_library: x, options="gui_debug" 5 | memory: host=32, guest=32 6 | romimage: file="/usr/share/bochs/BIOS-bochs-latest", address=0x00000000, options=none 7 | vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest" 8 | boot: disk 9 | floppy_bootsig_check: disabled=0 10 | # no floppya 11 | # no floppyb 12 | ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 13 | ata0-master: type=disk, path="harddisk.img", mode=flat 14 | ata0-slave: type=none 15 | ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15 16 | ata1-master: type=none 17 | ata1-slave: type=none 18 | ata2: enabled=false 19 | ata3: enabled=false 20 | optromimage1: file=none 21 | optromimage2: file=none 22 | optromimage3: file=none 23 | optromimage4: file=none 24 | optramimage1: file=none 25 | optramimage2: file=none 26 | optramimage3: file=none 27 | optramimage4: file=none 28 | pci: enabled=1, chipset=i440fx 29 | vga: extension=vbe, update_freq=5, realtime=1 30 | cpu: count=1:1:1, ips=4000000, quantum=16, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 31 | cpuid: level=6, stepping=3, model=3, family=6, vendor_string="AuthenticAMD", brand_string="AMD Athlon(tm) processor" 32 | cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true 33 | cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, avx_f16c=false 34 | cpuid: avx_fma=false, bmi=0, xop=false, fma4=false, tbm=false, x86_64=true, 1g_pages=false 35 | cpuid: pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true 36 | print_timestamps: enabled=0 37 | debugger_log: - 38 | magic_break: enabled=1 39 | port_e9_hack: enabled=0 40 | private_colormap: enabled=0 41 | clock: sync=none, time0=local, rtc_sync=0 42 | # clock: sync=realtime, time0=local, rtc_sync=1 43 | # no cmosimage 44 | log: - 45 | logprefix: %t%e%d 46 | debug: action=ignore 47 | info: action=report 48 | error: action=report 49 | panic: action=ask 50 | keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none 51 | mouse: type=ps2, enabled=false, toggle=ctrl+mbutton 52 | speaker: enabled=true, mode=system 53 | parport1: enabled=true, file=none 54 | parport2: enabled=false 55 | com1: enabled=true, mode=null 56 | com2: enabled=false 57 | com3: enabled=false 58 | com4: enabled=false 59 | -------------------------------------------------------------------------------- /os/makefile: -------------------------------------------------------------------------------- 1 | BUILD:= ./build 2 | SRC:=./src 3 | 4 | BOOT_INC:=$(SRC)/boot 5 | INCLUDE:=$(SRC)/kernel/include 6 | KERNEL:=$(SRC)/kernel 7 | 8 | BOCHS:=/usr/bin/bochs 9 | ASM=nasm 10 | CC=gcc 11 | LD=ld 12 | 13 | ENTRYPOINT = 0xC0010000 14 | 15 | 16 | ASM_FLAGS= -f bin 17 | ASM_KERNEL_FLAGS= -f elf 18 | 19 | CFLAGS = -I $(INCLUDE) -c -fno-builtin -m32 -fno-stack-protector \ 20 | -nostdlib -nostdinc -nostartfiles -nodefaultlibs -Wall -Wextra 21 | 22 | LDFLAGS = -m elf_i386 -s -Ttext $(ENTRYPOINT) 23 | 24 | 25 | .PHONY: clean test 26 | 27 | $(BUILD)/boot.bin: $(SRC)/boot/boot.asm $(BOOT_INC)/boot.inc 28 | $(ASM) -I $(BOOT_INC) $< -o $@ 29 | 30 | $(BUILD)/loader.bin: $(SRC)/boot/loader.asm $(BOOT_INC)/boot.inc 31 | $(ASM) $(ASM_FLAGS) -I $(BOOT_INC) $< -o $@ 32 | 33 | $(BUILD)/start.o: $(KERNEL)/start.asm 34 | $(ASM) $(ASM_KERNEL_FLAGS) -I $(BOOT_INC) $< -o $@ 35 | 36 | $(BUILD)/main.o: $(KERNEL)/main.c 37 | $(CC) $(CFLAGS) $< -o $@ 38 | 39 | $(BUILD)/kernel.bin: $(BUILD)/start.o \ 40 | $(BUILD)/main.o 41 | $(LD) $(LDFLAGS) $^ -o $@ 42 | 43 | $(BUILD)/harddisk.img: \ 44 | $(BUILD)/boot.bin \ 45 | $(BUILD)/loader.bin \ 46 | $(BUILD)/kernel.bin 47 | ifeq ("$(wildcard $(BUILD)/harddisk.img)", "") 48 | bximage -q -hd=16 -mode=create -sectsize=512 -imgmode=flat $@ 49 | endif 50 | dd if=$(BUILD)/boot.bin of=$@ bs=512 count=1 conv=notrunc 51 | dd if=$(BUILD)/loader.bin of=$@ bs=512 count=20 seek=2 conv=notrunc 52 | dd if=$(BUILD)/kernel.bin of=$@ bs=512 seek=100 count=200 conv=notrunc 53 | # dd if=$(BUILD)/app.bin of=$@ bs=512 seek=100 conv=notrunc 54 | 55 | bochs: $(BUILD)/harddisk.img 56 | @rm -rf $(BUILD)/harddisk.img.lock 57 | cd $(BUILD) && $(BOCHS) -q -f ../bochsrc 58 | 59 | clean: 60 | rm -rf $(BUILD)/*.o 61 | rm -rf $(BUILD)/harddisk.img* 62 | rm -rf $(BUILD)/boot.bin 63 | rm -rf $(BUILD)/loader.bin 64 | rm -rf $(BUILD)/kernel.bin 65 | 66 | 67 | -------------------------------------------------------------------------------- /os/src/boot/boot.asm: -------------------------------------------------------------------------------- 1 | %include "boot.inc" 2 | 3 | section boot align=16 vstart=BOOT_BASE_ADDR 4 | 5 | ;clean screen 6 | mov ax, 3 7 | int 0x10; 8 | 9 | ;setup segment register 10 | mov ax, cs 11 | mov ds, ax 12 | mov es, ax 13 | mov ss, ax 14 | mov fs, ax 15 | mov sp, BOOT_BASE_ADDR 16 | 17 | ;print message 18 | mov si, message 19 | call print 20 | 21 | call load_loader 22 | 23 | jmp 0:LOADER_BASE_ADDR 24 | 25 | finish: 26 | sti ; open interrupt 27 | hlt ; halt cpu 28 | jmp finish 29 | 30 | load_loader: 31 | ; read first sector 32 | mov eax, LOADER_START_SECTOR 33 | mov bx, LOADER_BASE_ADDR 34 | mov cx, 20 ; 10KB 35 | call read_disk 36 | 37 | ret 38 | 39 | READ_DISK 40 | 41 | print: 42 | cld 43 | .print_loop: 44 | lodsb 45 | or al, al 46 | jz .print_done 47 | 48 | mov ah, 0x0e; 49 | int 0x10; 50 | jmp .print_loop 51 | .print_done: 52 | ret 53 | 54 | message db "Boot is loading...", 13, 10, 0 55 | times 510-($-$$) db 0 56 | db 0x55, 0xaa 57 | -------------------------------------------------------------------------------- /os/src/boot/boot.inc: -------------------------------------------------------------------------------- 1 | BOOT_BASE_ADDR equ 0x7c00 2 | BASE_ADDRESS_LIMIT equ 0x100000; 1M 的空间 3 | 4 | LOADER_BASE_ADDR equ 0x900 5 | LOADER_START_SECTOR equ 2 6 | 7 | KERNEL_BASE_ADDR equ 0xc0010000 8 | KERNEL_START_SECTOR equ 100 9 | 10 | PAGE_DIR_TABLE_ADDR equ 0x4000 11 | PAGE_SIZE equ 0x1000 ; 4K = 4096 12 | 13 | ;0_0_0_0_0000_0_00_0_0000b 14 | ;G_D_L_A_LIMI_P_DP_S_TYPE 15 | 16 | GDT_G_BYTE equ 0_0_0_0_0000_0_00_0_0000b 17 | GDT_G_4K equ 1_0_0_0_0000_0_00_0_0000b 18 | 19 | GDT_DB_16 equ 0_0_0_0_0000_0_00_0_0000b 20 | GDT_DB_32 equ 0_1_0_0_0000_0_00_0_0000b 21 | 22 | GDT_L_32 equ 0_0_0_0_0000_0_00_0_0000b 23 | GDT_L_64 equ 0_0_1_0_0000_0_00_0_0000b 24 | 25 | GDT_P_ABS equ 0_0_0_0_0000_0_00_0_0000b 26 | GDT_P_PRE equ 0_0_0_0_0000_1_00_0_0000b 27 | 28 | GDT_DPL_0 equ 0_0_0_0_0000_0_00_0_0000b 29 | GDT_DPL_1 equ 0_0_0_0_0000_0_01_0_0000b 30 | GDT_DPL_2 equ 0_0_0_0_0000_0_10_0_0000b 31 | GDT_DPL_3 equ 0_0_0_0_0000_0_11_0_0000b 32 | 33 | GDT_S_SYSTEM equ 0_0_0_0_0000_0_00_0_0000b 34 | GDT_S_DATA equ 0_0_0_0_0000_0_00_1_0000b 35 | 36 | GDT_TYPE_DATA equ 0_0_0_0_0000_0_00_0_0000b 37 | GDT_TYPE_DATA_EXTEND_UP equ 0_0_0_0_0000_0_00_0_0000b 38 | GDT_TYPE_DATA_EXTEND_DOWN equ 0_0_0_0_0000_0_00_0_0100b 39 | GDT_TYPE_DATA_WRITE equ 0_0_0_0_0000_0_00_0_0010b 40 | 41 | GDT_TYPE_CODE equ 0_0_0_0_0000_0_00_0_1000b 42 | GDT_TYPE_CODE_COMPLY equ 0_0_0_0_0000_0_00_0_0100b 43 | GDT_TYPE_CODE_READ equ 0_0_0_0_0000_0_00_0_1010b 44 | 45 | GDT_TYPE_ACCESS equ 0_0_0_0_0000_0_00_0_0001b 46 | 47 | RPL0 equ 00b 48 | RPL1 equ 01b 49 | RPL2 equ 10b 50 | RPL3 equ 11b 51 | TI_GDT equ 000b 52 | TI_LDT equ 100b 53 | 54 | ; pde explain 55 | ; AVL_G_0_D_A_PCD_PWT_US_RW_P 56 | 57 | ; pte explain 58 | ; AVL_G_T_D_A_PCD_PWT_US_RW_P 59 | 60 | PG_P equ 1b ; exists 61 | PG_RW_R equ 00b ; write disable 62 | PG_RW_W equ 10b ; write enable 63 | PG_US_S equ 000b ; system user 64 | PG_US_U equ 100b ; normal user 65 | 66 | PT_NULL equ 0 67 | 68 | GDT_CODE_ATTRIBUTE equ (GDT_G_4K | GDT_DB_32 | GDT_P_PRE | GDT_S_DATA | GDT_TYPE_CODE_READ) 69 | GDT_DATA_ATTRIBUTE equ (GDT_G_4K | GDT_DB_32 | GDT_P_PRE | GDT_S_DATA | GDT_TYPE_DATA_WRITE) 70 | GDT_VIDEO_ATTRIBUTE equ (GDT_G_BYTE | GDT_DB_32 | GDT_P_PRE | GDT_S_DATA | GDT_TYPE_DATA_WRITE | GDT_DPL_3) 71 | 72 | PAGE_ATTRIBUTE equ PG_US_U | PG_RW_W | PG_P 73 | 74 | %macro GDTDescriptor 3; (base_address, limit, attribute) 75 | dw %2 & 0xffff 76 | dw %1 & 0xffff 77 | db (%1 >> 16) & 0xff 78 | dw ((%2 >> 8) & 0x0f00) | (%3 & 0xf0ff) 79 | db (%1 >> 24) & 0xff 80 | %endmacro 81 | 82 | 83 | %macro READ_DISK 0 84 | read_disk: 85 | ;从硬盘读取一个逻辑扇区 86 | ; EAX = 逻辑扇区号 87 | ; DS: EBX = 目标缓冲区地址 88 | ; CX, 读取的扇区数量 89 | pusha 90 | 91 | push eax 92 | 93 | ; 设置需要读取的扇区数 94 | mov dx, 0x1f2 95 | mov al, cl 96 | out dx, al 97 | 98 | pop eax 99 | 100 | ; 写入 LBA地址 7 ~ 0 101 | inc dx ;0x1f3 102 | out dx, al; 103 | 104 | ; 写入 LBA地址 15 ~ 8 105 | inc dx ;0x1f4 106 | shr eax, 8 107 | out dx, al 108 | 109 | ; 写入 LBA地址 23 ~ 16 110 | inc dx ;0x1f5 111 | shr eax, 8 112 | out dx, al 113 | 114 | ; 写入 第一硬盘 LBA地址27~24 115 | inc dx ;0x1f6 116 | shr eax, 8 117 | and al, 0x0f 118 | or al, 0xe0 119 | out dx,al 120 | 121 | ; 写入读命令 122 | inc dx ;0x1f7 123 | mov al, 0x20 124 | out dx,al 125 | 126 | .waits: 127 | in al,dx 128 | and al,0x88 129 | cmp al,0x08 130 | jnz .waits ; 不忙,且硬盘已准备好数据传输 131 | 132 | mov ax, cx 133 | mov dx, 256 ;总共要读取的字数 134 | mul dx 135 | mov cx, ax 136 | mov dx, 0x1f0 ; 读取端口号 137 | 138 | .readw: 139 | in ax,dx ; 读取输入 140 | mov [ebx], ax ; 转移到内存 141 | add ebx , 2; 一次读取两个字节 142 | 143 | loop .readw 144 | 145 | popa 146 | 147 | ret 148 | %endmacro -------------------------------------------------------------------------------- /os/src/boot/elf.inc: -------------------------------------------------------------------------------- 1 | ELF_HEADER_OFFSET_TYPE equ 16; /* Object file type */ 2 | ELF_HEADER_OFFSET_MACHINE equ 18; /* Architecture */ 3 | ELF_HEADER_OFFSET_VERSION equ 20; /* Object file version */ 4 | ELF_HEADER_OFFSET_ENTRY equ 24; /* Entry point virtual address */ 5 | ELF_HEADER_OFFSET_PHOFF equ 28; /* Program header table file offset */ 6 | ELF_HEADER_OFFSET_SHOFF equ 32; /* Section header table file offset */ 7 | ELF_HEADER_OFFSET_FLAGS equ 36; /* Processor-specific flags */ 8 | ELF_HEADER_OFFSET_EHSIZE equ 40; /* ELF header size in bytes */ 9 | ELF_HEADER_OFFSET_PHENTSIZE equ 42; /* Program header table entry size */ 10 | ELF_HEADER_OFFSET_PHNUM equ 44; /* Program header table entry count */ 11 | ELF_HEADER_OFFSET_SHENTSIZE equ 46; /* Section header table entry size */ 12 | ELF_HEADER_OFFSET_SHNUM equ 48; /* Section header table entry count */ 13 | ELF_HEADER_OFFSET_SHSTRNDX equ 50; /* Section header string table index */ 14 | 15 | ELF_PROGRAM_OFFSET_TYPE equ 0; /* Segment type */ 16 | ELF_PROGRAM_OFFSET_OFFSET equ 4; /* Segment file offset */ 17 | ELF_PROGRAM_OFFSET_VADDR equ 8; /* Segment virtual address */ 18 | ELF_PROGRAM_OFFSET_PADDR equ 12; /* Segment physical address */ 19 | ELF_PROGRAM_OFFSET_FILESZ equ 16; /* Segment size in file */ 20 | ELF_PROGRAM_OFFSET_MEMSZ equ 20; /* Segment size in memory */ 21 | ELF_PROGRAM_OFFSET_FLAGS equ 24; /* Segment flags */ 22 | ELF_PROGRAM_OFFSET_ALIGN equ 28; /* Segment alignment */ 23 | -------------------------------------------------------------------------------- /os/src/boot/loader.asm: -------------------------------------------------------------------------------- 1 | %include "boot.inc" 2 | %include "elf.inc" 3 | 4 | LOADER_STACK_TOP equ LOADER_BASE_ADDR 5 | 6 | section loader vstart=LOADER_BASE_ADDR 7 | jmp start 8 | 9 | gdt_base: GDTDescriptor 0, 0, 0 10 | gdt_code: GDTDescriptor 0, 0xfffff, GDT_CODE_ATTRIBUTE 11 | gdt_data: GDTDescriptor 0, 0xfffff, GDT_DATA_ATTRIBUTE 12 | gdt_video: GDTDescriptor 0xb8000, 0x0ffff, GDT_VIDEO_ATTRIBUTE 13 | gdt_size: equ ($ - gdt_base) 14 | gdt_limit: equ (gdt_size - 1) 15 | gdt_ptr: dw gdt_limit 16 | dd gdt_base 17 | 18 | SELECTOR_CODE equ (1 << 3) | TI_GDT | RPL0 19 | SELECTOR_DATA equ (2 << 3) | TI_GDT | RPL0 20 | SELECTOR_VIDEO equ (3 << 3) | TI_GDT | RPL0 21 | 22 | total_memory_bytes dd 0 23 | ards_count dw 0 24 | ards_buffer times 128 - ($ - $$) db 0 25 | 26 | start: 27 | ; xchg bx, bx 28 | 29 | mov si, message_start_loader 30 | call print 31 | 32 | ; xchg bx, bx 33 | ; detect memory 34 | xor ebx, ebx 35 | mov edx, 0x534d4150 36 | mov di, ards_buffer 37 | 38 | mov si, message_detect_momory_e820 39 | call print 40 | 41 | ; 内存检测可能会修改内存内容,待验证 42 | 43 | .check_memory_r820: 44 | mov eax, 0x0000e820 45 | mov ecx, 20 46 | int 0x15 47 | 48 | jc .get_memory_e801 49 | 50 | add di, cx 51 | inc word [ards_count] 52 | cmp ebx, 0 53 | jnz .check_memory_r820 54 | 55 | mov cx, [ards_count] 56 | mov ebx, ards_buffer 57 | xor edx, edx 58 | 59 | .get_max_memory_area: 60 | 61 | mov eax, [ebx] 62 | add eax, [ebx + 8] 63 | add ebx, 20 64 | cmp edx, eax 65 | jge .next_ards 66 | mov edx, eax 67 | 68 | .next_ards: 69 | loop .get_max_memory_area 70 | jmp .get_memory_ok 71 | 72 | .get_memory_e801: 73 | mov si, message_detect_momory_e801 74 | call print 75 | 76 | mov ax, 0xe801 77 | mul cx 78 | shl edx, 16 79 | and eax, 0x0000ffff 80 | or edx, eax 81 | add edx, 0x100000 82 | mov esi, edx 83 | 84 | xor eax, eax 85 | mov ax, bx 86 | mov ecx, 0x10000 87 | mul ecx 88 | add esi, eax 89 | mov edx, esi 90 | jmp .get_memory_ok 91 | 92 | .get_memory_e88: 93 | mov si, message_detect_momory_e88 94 | call print 95 | 96 | mov ah, 0x88 97 | int 0x15 98 | jc .get_memory_failure 99 | 100 | and eax, 0x0000ffff 101 | 102 | mov cx, 0x400 103 | mul cx 104 | 105 | shl edx, 16 106 | or edx, eax 107 | and edx, 0x100000 108 | 109 | .get_memory_ok: 110 | mov [total_memory_bytes], edx 111 | 112 | ; xchg bx, bx 113 | ; prepare for protect mode 114 | mov si, message_prepare_protect_mode 115 | call print 116 | 117 | cli 118 | 119 | lgdt [gdt_ptr] 120 | 121 | ; open a20 address line 122 | in al, 0x92 123 | or al, 0000_0010b 124 | out 0x92, al 125 | 126 | mov eax, cr0 127 | or eax, 1 128 | mov cr0, eax 129 | 130 | ; xchg bx, bx 131 | 132 | jmp dword SELECTOR_CODE:protect_mode_start 133 | 134 | .get_memory_failure: 135 | finish: 136 | sti ; open interrupt 137 | hlt ; halt cpu 138 | jmp finish 139 | 140 | 141 | print: 142 | cld 143 | .print_loop: 144 | lodsb 145 | or al, al 146 | jz .print_done 147 | 148 | mov ah, 0x0e; 149 | int 0x10; 150 | jmp .print_loop 151 | .print_done: 152 | ret 153 | 154 | message_start_loader db "Loader is starting...", 13, 10, 0 155 | message_detect_momory_e820 db "Detecting memory e820...", 13, 10, 0 156 | message_detect_momory_e801 db "Detecting memory e801...", 13, 10, 0 157 | message_detect_momory_e88 db "Detecting memory e88...", 13, 10, 0 158 | message_prepare_protect_mode db "Preparing protect mode...", 13, 10, 0 159 | ; placeholder times 1024 - ($ - $$) db 0xff 160 | 161 | [bits 32] 162 | 163 | protect_mode_start: 164 | ; xchg bx, bx 165 | 166 | mov ax, SELECTOR_DATA 167 | mov ds, ax 168 | mov es, ax 169 | mov ss, ax 170 | mov esp, LOADER_STACK_TOP 171 | mov ax, SELECTOR_VIDEO 172 | mov gs, ax 173 | 174 | call setup_page 175 | call load_kernel 176 | call init_kernel 177 | 178 | mov esp, KERNEL_BASE_ADDR 179 | jmp SELECTOR_CODE: KERNEL_BASE_ADDR 180 | 181 | memcpy: 182 | ; memcpy(dst, src, size) 183 | 184 | cld 185 | push ebp 186 | mov ebp, esp 187 | push ecx 188 | 189 | mov edi, [ebp + 8] 190 | mov esi, [ebp + 12] 191 | mov ecx, [ebp + 16] 192 | rep movsb 193 | 194 | pop ecx 195 | pop ebp 196 | ret 197 | 198 | 199 | init_kernel: 200 | ; xchg bx, bx 201 | xor eax, eax 202 | xor ebx, ebx 203 | xor ecx, ecx 204 | xor edx, edx 205 | 206 | mov ax, [KERNEL_BASE_ADDR + ELF_HEADER_OFFSET_TYPE] 207 | cmp ax, 2 208 | jne .failure ; invalid executable file 209 | 210 | mov dx, [KERNEL_BASE_ADDR + ELF_HEADER_OFFSET_PHENTSIZE] 211 | mov ebx, [KERNEL_BASE_ADDR + ELF_HEADER_OFFSET_PHOFF] 212 | add ebx, KERNEL_BASE_ADDR 213 | mov cx, [KERNEL_BASE_ADDR + ELF_HEADER_OFFSET_PHNUM] 214 | 215 | .each_segment: 216 | cmp byte [ebx + 0], PT_NULL 217 | je .PT_NULL 218 | 219 | push dword [ebx + ELF_PROGRAM_OFFSET_FILESZ] 220 | mov eax, [ebx + ELF_PROGRAM_OFFSET_OFFSET] 221 | add eax, KERNEL_BASE_ADDR 222 | push eax 223 | push dword [ebx + ELF_PROGRAM_OFFSET_VADDR] 224 | call memcpy 225 | add esp, 12 226 | 227 | .PT_NULL: 228 | add ebx, edx 229 | loop .each_segment 230 | ret 231 | 232 | .failure: 233 | sti 234 | hlt 235 | jmp .failure 236 | 237 | ;----------------------------------- 238 | 239 | load_kernel: 240 | mov eax, KERNEL_START_SECTOR 241 | mov ebx, KERNEL_BASE_ADDR 242 | mov cx, 200 ; 100KB 243 | call read_disk 244 | ret 245 | 246 | ;------------------------------------ 247 | 248 | setup_page: 249 | 250 | ; xchg bx, bx 251 | mov ecx, PAGE_SIZE * 3 252 | mov esi, 0 253 | 254 | .reset_page: 255 | mov byte [PAGE_DIR_TABLE_ADDR + esi], 0 256 | inc esi 257 | loop .reset_page 258 | 259 | ; xchg bx, bx 260 | 261 | .create_pde: ; PDE 页目录表,只有一个 262 | 263 | ; 0000_0000_00b 对应的页表 264 | ; 设置基础页目录,使前 1M 内存映射到自己 265 | ; 使虚拟地址 3G 后的内存也映射到 1M 内存中 266 | 267 | mov eax, PAGE_DIR_TABLE_ADDR + PAGE_SIZE; 268 | or eax, PAGE_ATTRIBUTE 269 | mov [PAGE_DIR_TABLE_ADDR + 0], eax 270 | mov [PAGE_DIR_TABLE_ADDR + (0x300 * 4)], eax; 第 0x300 个目录项,每个目录项占四个字节 271 | 272 | ; 使最高的目录指向自己,方便修改,这将浪费一个表项,使虚拟地址最高的 4M 无法访问, 273 | ; 不过也没关系,一般程序不会用到那么高的地址 274 | 275 | mov eax, PAGE_DIR_TABLE_ADDR 276 | or eax, PAGE_ATTRIBUTE 277 | mov [PAGE_DIR_TABLE_ADDR + (0x3ff * 4)], eax; 278 | 279 | ; 低端 1M 内存 / 4KB = 256 280 | 281 | ; xchg bx, bx 282 | 283 | mov ebx, PAGE_DIR_TABLE_ADDR + PAGE_SIZE; 284 | mov ecx, (BASE_ADDRESS_LIMIT / PAGE_SIZE) ; 256 285 | mov esi, 0 286 | mov edx, PAGE_ATTRIBUTE 287 | 288 | .create_pte: 289 | mov [ebx + esi * 4], edx 290 | add edx, PAGE_SIZE 291 | inc esi 292 | loop .create_pte 293 | 294 | ; 设置 CR3 寄存器 295 | mov eax, PAGE_DIR_TABLE_ADDR 296 | mov cr3, eax 297 | 298 | ; 打开分页功能 打开cr0的pg位(第31位) 299 | mov eax, cr0 300 | or eax, 10000000_00000000_00000000_00000000b 301 | mov cr0, eax 302 | 303 | ret 304 | 305 | READ_DISK 306 | -------------------------------------------------------------------------------- /os/src/kernel/include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef ONIX_CONFIG 2 | 3 | #define BASE_VIDEO_ADDRESS (0xb8000) 4 | #define VIDEO_CHAR_SIZE (2) 5 | 6 | #endif -------------------------------------------------------------------------------- /os/src/kernel/main.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | int main() 4 | { 5 | char *video = BASE_VIDEO_ADDRESS; 6 | for (int i = 0; i < 52; i++) 7 | { 8 | video[i * VIDEO_CHAR_SIZE] = 'A' + i; 9 | } 10 | while (1) 11 | { 12 | 13 | } 14 | return 0; 15 | } -------------------------------------------------------------------------------- /os/src/kernel/start.asm: -------------------------------------------------------------------------------- 1 | %include "boot.inc" 2 | 3 | bits 32 4 | [section .text] 5 | 6 | global _start 7 | extern main 8 | 9 | _start: 10 | call main 11 | jmp $ -------------------------------------------------------------------------------- /os/src/tests/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #pragma pack(1) 5 | 6 | typedef struct 7 | { 8 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 9 | // Elf32_Half e_type; /* Object file type */ 10 | // Elf32_Half e_machine; /* Architecture */ 11 | // Elf32_Word e_version; /* Object file version */ 12 | // Elf32_Addr e_entry; /* Entry point virtual address */ 13 | // Elf32_Off e_phoff; /* Program header table file offset */ 14 | // Elf32_Off e_shoff; /* Section header table file offset */ 15 | // Elf32_Word e_flags; /* Processor-specific flags */ 16 | // Elf32_Half e_ehsize; /* ELF header size in bytes */ 17 | // Elf32_Half e_phentsize; /* Program header table entry size */ 18 | // Elf32_Half e_phnum; /* Program header table entry count */ 19 | // Elf32_Half e_shentsize; /* Section header table entry size */ 20 | // Elf32_Half e_shnum; /* Section header table entry count */ 21 | // Elf32_Half e_shstrndx; /* Section header string table index */ 22 | } ELFTest; 23 | 24 | typedef struct 25 | { 26 | // Elf32_Word p_type; /* Segment type */ 27 | // Elf32_Off p_offset; /* Segment file offset */ 28 | // Elf32_Addr p_vaddr; /* Segment virtual address */ 29 | // Elf32_Addr p_paddr; /* Segment physical address */ 30 | // Elf32_Word p_filesz; /* Segment size in file */ 31 | // Elf32_Word p_memsz; /* Segment size in memory */ 32 | // Elf32_Word p_flags; /* Segment flags */ 33 | // Elf32_Word p_align; /* Segment alignment */ 34 | } Elf32_Header; 35 | 36 | int main() 37 | { 38 | std::cout << sizeof(Elf32_Header) << std::endl; 39 | } 40 | -------------------------------------------------------------------------------- /snapshots/compile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenBaby/learning-assembly/42312cc5c81cc2dc62bc3d14c5dd4ecaf052d989/snapshots/compile.jpg -------------------------------------------------------------------------------- /snapshots/edit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenBaby/learning-assembly/42312cc5c81cc2dc62bc3d14c5dd4ecaf052d989/snapshots/edit.jpg -------------------------------------------------------------------------------- /snapshots/run.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenBaby/learning-assembly/42312cc5c81cc2dc62bc3d14c5dd4ecaf052d989/snapshots/run.jpg -------------------------------------------------------------------------------- /snapshots/single.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenBaby/learning-assembly/42312cc5c81cc2dc62bc3d14c5dd4ecaf052d989/snapshots/single.jpg -------------------------------------------------------------------------------- /tutotrial/bochsrc: -------------------------------------------------------------------------------- 1 | # configuration file generated by Bochs 2 | plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, iodebug=true 3 | config_interface: textconfig 4 | display_library: x, options="gui_debug" 5 | memory: host=32, guest=32 6 | romimage: file="/usr/share/bochs/BIOS-bochs-latest", address=0x00000000, options=none 7 | vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest" 8 | boot: disk 9 | floppy_bootsig_check: disabled=0 10 | # no floppya 11 | # no floppyb 12 | ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 13 | ata0-master: type=disk, path="harddisk.img", mode=flat 14 | ata0-slave: type=none 15 | ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15 16 | ata1-master: type=none 17 | ata1-slave: type=none 18 | ata2: enabled=false 19 | ata3: enabled=false 20 | optromimage1: file=none 21 | optromimage2: file=none 22 | optromimage3: file=none 23 | optromimage4: file=none 24 | optramimage1: file=none 25 | optramimage2: file=none 26 | optramimage3: file=none 27 | optramimage4: file=none 28 | pci: enabled=1, chipset=i440fx 29 | vga: extension=vbe, update_freq=5, realtime=1 30 | cpu: count=1:1:1, ips=4000000, quantum=16, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 31 | cpuid: level=6, stepping=3, model=3, family=6, vendor_string="AuthenticAMD", brand_string="AMD Athlon(tm) processor" 32 | cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true 33 | cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, avx_f16c=false 34 | cpuid: avx_fma=false, bmi=0, xop=false, fma4=false, tbm=false, x86_64=true, 1g_pages=false 35 | cpuid: pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true 36 | print_timestamps: enabled=0 37 | debugger_log: - 38 | magic_break: enabled=0 39 | port_e9_hack: enabled=0 40 | private_colormap: enabled=0 41 | clock: sync=none, time0=local, rtc_sync=0 42 | # no cmosimage 43 | log: - 44 | logprefix: %t%e%d 45 | debug: action=ignore 46 | info: action=report 47 | error: action=report 48 | panic: action=ask 49 | keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none 50 | mouse: type=ps2, enabled=false, toggle=ctrl+mbutton 51 | speaker: enabled=true, mode=system 52 | parport1: enabled=true, file=none 53 | parport2: enabled=false 54 | com1: enabled=true, mode=null 55 | com2: enabled=false 56 | com3: enabled=false 57 | com4: enabled=false 58 | -------------------------------------------------------------------------------- /tutotrial/boot.asm: -------------------------------------------------------------------------------- 1 | mov ax, 3; 设置功能 2 | int 0x10; 调用中断清除屏幕 3 | 4 | mov ah, 0x0e; 字符颜色 5 | mov al, 'B'; 字符数据 6 | int 0x10; 调用中断显示字符 7 | 8 | jmp $ ; 跳转到当前行,阻塞继续执行 9 | 10 | times 510-($-$$) db 0 11 | db 0x55, 0xaa 12 | -------------------------------------------------------------------------------- /x86/app.asm: -------------------------------------------------------------------------------- 1 | ;代码清单16-2 2 | ;文件名:c16.asm 3 | ;文件说明:用户程序 4 | ;创建日期:2012-05-25 13:53 5 | 6 | program_length dd program_end ;程序总长度#0x00 7 | entry_point dd start ;程序入口点#0x04 8 | salt_position dd salt_begin ;SALT表起始偏移量#0x08 9 | salt_items dd (salt_end-salt_begin)/256 ;SALT条目数#0x0C 10 | 11 | ;------------------------------------------------------------------------------- 12 | 13 | ;符号地址检索表 14 | salt_begin: 15 | 16 | PrintString db '@PrintString' 17 | times 256-($-PrintString) db 0 18 | 19 | TerminateProgram db '@TerminateProgram' 20 | times 256-($-TerminateProgram) db 0 21 | ;------------------------------------------------------------------------------- 22 | 23 | reserved times 256*500 db 0 ;保留一个空白区,以演示分页 24 | 25 | ;------------------------------------------------------------------------------- 26 | ReadDiskData db '@ReadDiskData' 27 | times 256-($-ReadDiskData) db 0 28 | 29 | PrintDwordAsHex db '@PrintDwordAsHexString' 30 | times 256-($-PrintDwordAsHex) db 0 31 | 32 | salt_end: 33 | 34 | message_0 db 0x0d,0x0a, 35 | db ' ............User task is running with ' 36 | db 'paging enabled!............',0x0d,0x0a,0 37 | 38 | space db 0x20,0x20,0 39 | 40 | ;------------------------------------------------------------------------------- 41 | [bits 32] 42 | ;------------------------------------------------------------------------------- 43 | 44 | start: 45 | 46 | mov ebx,message_0 47 | call far [PrintString] 48 | 49 | xor esi,esi 50 | mov ecx,88 51 | .b1: 52 | mov ebx,space 53 | call far [PrintString] 54 | 55 | mov edx,[esi*4] 56 | call far [PrintDwordAsHex] 57 | 58 | inc esi 59 | loop .b1 60 | 61 | call far [TerminateProgram] ;退出,并将控制权返回到核心 62 | 63 | ;------------------------------------------------------------------------------- 64 | program_end: -------------------------------------------------------------------------------- /x86/backup/app_clock_interrupt.asm: -------------------------------------------------------------------------------- 1 | 2 | section header vstart=0; 3 | length dd program_end 4 | entry dw start; 偏移地址 5 | dd section.code.start; 段地址 6 | table dw (header_end - code_segment)/4 ; 段重定位表项个数 7 | code_segment dd section.code.start; 8 | data_segment dd section.data.start; 9 | stack_segment dd section.stack.start; 10 | header_end: 11 | 12 | section code align=16 vstart=0 13 | 14 | start: 15 | ; xchg bx, bx 16 | 17 | mov ax, [stack_segment] 18 | mov ss, ax 19 | mov sp, stack_end 20 | 21 | mov ax, [data_segment] 22 | mov ds, ax 23 | 24 | call clear_screen 25 | 26 | mov si, message 27 | call print 28 | 29 | mov al, 0x70 30 | mov bl, 4 31 | mul bl 32 | mov bx, ax 33 | 34 | cli 35 | 36 | push es 37 | mov ax, 0x0000 38 | mov es, ax 39 | mov word [es:bx], int_0x70 40 | mov word [es:bx+2], cs 41 | pop es 42 | 43 | mov al,0x0b ;RTC寄存器B 44 | or al,0x80 ;阻断NMI 45 | out 0x70,al 46 | mov al,0x12 ;设置寄存器B,禁止周期性中断,开放更 47 | out 0x71,al ;新结束后中断,BCD码,24小时制 48 | 49 | mov al,0x0c 50 | out 0x70,al 51 | in al,0x71 ;读RTC寄存器C,复位未决的中断状态 52 | 53 | in al,0xa1 ;读8259从片的IMR寄存器 54 | and al,0xfe ;清除bit 0(此位连接RTC) 55 | out 0xa1,al ;写回此寄存器 56 | 57 | sti ;重新开放中断 58 | 59 | .idle: 60 | hlt ;使CPU进入低功耗状态,直到用中断唤醒 61 | jmp .idle 62 | 63 | jmp $ 64 | 65 | int_0x70: 66 | pusha 67 | push ds 68 | push es 69 | 70 | mov al,0x0a ;阻断NMI。当然,通常是不必要的 71 | or al,0x80 72 | out 0x70,al 73 | in al,0x71 ;读寄存器A 74 | test al,0x80 ;测试第7位UIP 75 | jnz .return ;以上代码对于更新周期结束中断来说 76 | ;是不必要的 77 | 78 | xor al,al 79 | or al,0x80 80 | out 0x70,al 81 | in al,0x71 ;读RTC当前时间(秒) 82 | call bcd_to_ascii 83 | mov [seconds], ax 84 | 85 | 86 | mov al, 2 87 | or al, 0x80 88 | out 0x70, al 89 | in al, 0x71 ;读RTC当前时间(秒) 90 | call bcd_to_ascii 91 | mov [minutes], ax 92 | 93 | mov al, 4 94 | or al, 0x80 95 | out 0x70, al 96 | in al, 0x71 ;读RTC当前时间(秒) 97 | call bcd_to_ascii 98 | mov [hours], ax 99 | 100 | mov al, 7 101 | or al, 0x80 102 | out 0x70, al 103 | in al, 0x71 ;读RTC当前时间(日) 104 | call bcd_to_ascii 105 | mov [days], ax 106 | 107 | 108 | mov al, 8 109 | or al, 0x80 110 | out 0x70, al 111 | in al, 0x71 ;读RTC当前时间(月) 112 | call bcd_to_ascii 113 | mov [months], ax 114 | 115 | mov al, 9 116 | or al, 0x80 117 | out 0x70, al 118 | in al, 0x71 ;读RTC当前时间(年) 119 | call bcd_to_ascii 120 | mov [years], ax 121 | 122 | mov al,0x0c ;寄存器C的索引。且开放NMI 123 | out 0x70,al 124 | in al,0x71 ;读一下RTC的寄存器C,否则只发生一次中断 125 | ;此处不考虑闹钟和周期性中断的情况 126 | ; 将 datetime 处的内容拷贝到 显存,以显示时间 127 | mov ax,0xb800 128 | mov es,ax 129 | 130 | mov si, datetime 131 | mov di, 12 * 160 + 30 * 2 132 | 133 | .showtime: 134 | mov ax, [si] 135 | cmp ax, 0 136 | je .return 137 | movsb 138 | inc di 139 | jmp .showtime 140 | 141 | .return: 142 | 143 | mov al,0x20 ;中断结束命令EOI 144 | out 0xa0,al ;向从片发送 145 | out 0x20,al ;向主片发送 146 | 147 | pop es 148 | pop ds 149 | popa 150 | 151 | iret 152 | 153 | 154 | bcd_to_ascii: ;BCD码转ASCII 155 | ;输入:AL=bcd码 156 | ;输出:AX=ascii 157 | ; 采用小端方式,可以直接写入内存 158 | ; 设 AX = 0x0028 159 | 160 | mov ah, al ;分拆成两个数字 0x2828 161 | and al, 0xf0 ;仅保留高4位 0x2820 162 | shr al, 4; ;0x2802 163 | add al, 0x30 ;转换成ASCII 0x2832 164 | 165 | and ah, 0x0f ; 0x0832 166 | add ah, 0x30 ; 0x3832; 结果 167 | 168 | ret 169 | 170 | clear_screen: 171 | mov ax, 0x3 172 | int 0x10; 173 | ret 174 | 175 | print: 176 | cld 177 | .print_loop: 178 | lodsb 179 | or al, al 180 | jz .print_done 181 | 182 | mov ah, 0x0e ; 0000 黑色背景 1110 浅灰色,默认颜色 183 | int 0x10; 184 | jmp .print_loop 185 | 186 | .print_done: 187 | ret 188 | 189 | code_end: 190 | 191 | section data align=16 vstart=0; 192 | message db 'Hello world!!!', 0 193 | datetime db '20' 194 | years db '21-' 195 | months db '02-' 196 | days db '02 ' 197 | hours db '02:' 198 | minutes db '02:' 199 | seconds db '02', 0 200 | data_end: 201 | 202 | section stack align=16 vstart=0; 203 | ; resb 256 204 | times 0x100 db 0; 干掉 warning 205 | stack_end: 206 | 207 | section trail align=16; 208 | ending db 'program ending', 0 209 | program_end: 210 | -------------------------------------------------------------------------------- /x86/backup/app_harddisk_read_write.asm: -------------------------------------------------------------------------------- 1 | 2 | section header vstart=0; 3 | length dd program_end 4 | entry dw start; 偏移地址 5 | dd section.code.start; 段地址 6 | table dw (header_end - code_segment)/4 ; 段重定位表项个数 7 | code_segment dd section.code.start; 8 | data_segment dd section.data.start; 9 | stack_segment dd section.stack.start; 10 | header_end: 11 | 12 | section code align=16 vstart=0 13 | 14 | start: 15 | ; xchg bx, bx 16 | 17 | mov ax, [stack_segment] 18 | mov ss, ax 19 | mov sp, stack_end 20 | 21 | mov ax, [data_segment] 22 | mov ds, ax 23 | 24 | call clear_screen 25 | 26 | mov si, message 27 | call print 28 | 29 | jmp $ 30 | 31 | clear_screen: 32 | mov ax, 0x3 33 | int 0x10; 34 | ret 35 | 36 | write_harddisk: 37 | pusha 38 | push ds 39 | 40 | mov bx, message 41 | mov byte [bx], 'K' 42 | 43 | mov si, 100 44 | xor di, di 45 | 46 | mov ax, 0x1000 47 | mov ds, ax 48 | 49 | mov dx, [2] 50 | mov ax, [0] 51 | mov bx, 512 52 | div bx 53 | cmp dx, 0 54 | je .direct 55 | inc ax 56 | 57 | .direct: 58 | 59 | ; xchg bx, bx; 60 | mov cx, ax; 记录写入扇区数量 61 | 62 | mov dx, 0x1f2 63 | ; mov al, al 64 | out dx, al ; 写入数量 65 | 66 | inc dx ; 0x1f3 67 | mov ax, si; 68 | out dx, al; lba 地址 7-0 69 | 70 | inc dx; 0x1f4 71 | mov al, ah; 72 | out dx, al; lba address 15 - 8 73 | 74 | inc dx; 0x1f5 75 | mov ax, di 76 | out dx, al ; lba address 23 - 16 77 | 78 | inc dx; 0x1f6 79 | mov al, 0xe0 80 | or al, ah; lba address 27-24 81 | out dx, al; 82 | 83 | inc dx; 0x1f7 84 | mov al, 0x30; command write 85 | out dx, al 86 | 87 | ; xchg bx, bx; 88 | 89 | .waits: 90 | in al, dx 91 | and al, 0x88 92 | cmp al, 0x08 93 | jnz .waits 94 | 95 | ; xchg bx, bx; 96 | xor bx, bx 97 | 98 | .write_sector: 99 | push cx 100 | 101 | mov cx, 256 102 | mov dx, 0x1f0 103 | 104 | .readw: 105 | mov ax, [bx] 106 | out dx, ax 107 | ; in ax, dx 108 | ; mov [bx], ax 109 | add bx, 2 110 | nop 111 | nop 112 | nop 113 | nop 114 | nop 115 | loop .readw 116 | 117 | pop cx 118 | loop .write_sector 119 | 120 | pop ds 121 | popa 122 | ret 123 | 124 | get_cursor: 125 | ; 将光标位置 写入 AX 寄存器 126 | push dx 127 | 128 | mov dx, 0x3d4; 索引寄存器端口号 129 | mov al, 0x0e ; 光标寄存器 高八位 130 | out dx, al 131 | 132 | mov dx, 0x3d5; 数据端口号 133 | in al, dx; 获得高八位 134 | mov ah, al; 135 | 136 | mov dx, 0x3d4; 索引寄存器端口号 137 | mov al, 0x0f ; 光标寄存器 低八位 138 | out dx, al 139 | 140 | mov dx, 0x3d5; 数据端口号 141 | in al, dx; 获得低八位 142 | 143 | pop dx 144 | ret; 结果存在 ax 寄存器中 145 | 146 | set_cursor: 147 | ; 将 AX 寄存器中的光标位置 写入显卡 148 | 149 | push dx 150 | push bx 151 | push ax 152 | 153 | mov bx, ax; 154 | 155 | mov dx, 0x3d4; 索引寄存器端口号 156 | mov al, 0x0e ; 光标寄存器 高八位 157 | out dx, al 158 | 159 | mov dx, 0x3d5; 数据端口号 160 | mov al, bh; 获得高八位 161 | out dx, al; 写入高八位 162 | 163 | mov dx, 0x3d4; 索引寄存器端口号 164 | mov al, 0x0f ; 光标寄存器 低八位 165 | out dx, al 166 | 167 | mov dx, 0x3d5; 数据端口号 168 | mov al, bl; 获得低八位 169 | out dx, al; 写入低八位 170 | 171 | pop ax 172 | pop bx 173 | pop dx 174 | ret; 175 | 176 | scroll_screen: 177 | ; 向上滚动 Al 行; 178 | 179 | pusha 180 | push ds 181 | push es 182 | 183 | mov bx, 0xb800; 184 | mov ds, bx; 185 | mov es, bx; 186 | 187 | cld; 递增方向 188 | 189 | push ax; 190 | 191 | mov ah, 80 * 2; 192 | mul ah 193 | mov si, ax; 194 | mov di, 0x00 195 | 196 | mov cx, 80 * 24; 197 | rep movsw 198 | 199 | pop ax; 200 | mov ah, 80; 201 | mul ah; 计算字符数量 202 | 203 | ;清除新出现的行 204 | mov bx, 25 * 80 * 2; 205 | mov cx, ax; 206 | shl ax, 1; 207 | sub bx, ax; 208 | mov si, ax; 209 | 210 | .cls: 211 | sub si, 2 212 | mov word [es:bx + si], 0x0720; 0x07 默认颜色; 0x20 空格 213 | loop .cls 214 | 215 | pop es 216 | pop ds 217 | popa 218 | 219 | ret 220 | 221 | print: 222 | cld 223 | .print_loop: 224 | lodsb 225 | or al, al 226 | jz .print_done 227 | 228 | mov ah, 0x0e ; 0000 黑色背景 1110 浅灰色,默认颜色 229 | int 0x10; 230 | jmp .print_loop 231 | 232 | .print_done: 233 | ret 234 | 235 | code_end: 236 | 237 | section data align=16 vstart=0; 238 | message db 'Hello world!!!', 0 239 | data_end: 240 | 241 | section stack align=16 vstart=0; 242 | ; resb 256 243 | times 0x100 db 0; 干掉 warning 244 | stack_end: 245 | 246 | section trail align=16; 247 | ending db 'program ending', 0 248 | program_end: 249 | -------------------------------------------------------------------------------- /x86/backup/chapter_11.asm: -------------------------------------------------------------------------------- 1 | section mbr align=16 vstart=0x7c00 2 | mov ax, 0x0003; clear screen 3 | int 0x10; 4 | 5 | ;设置堆栈段和栈指针 6 | mov ax,cs 7 | mov ss,ax 8 | mov sp,0x7c00 9 | 10 | ; xchg bx, bx 11 | ;计算GDT所在的逻辑段地址 12 | mov ax,[cs:gdt_base] ;低16位 0x7e00 13 | mov dx,[cs:gdt_base+0x02] ;高16位 0x0000 14 | mov bx,16 15 | div bx ;商(ax) 余数(dx) 16 | mov ds,ax ;令 DS 指向该段以进行操作 17 | mov bx,dx ;段内起始偏移地址 18 | 19 | ;创建0#描述符,它是空描述符,这是处理器的要求 20 | xor si, si 21 | mov dword [bx+si],0x00 22 | 23 | add si, 4; 24 | mov dword [bx+si],0x00 25 | 26 | ;创建#1描述符,保护模式下的代码段描述符 27 | add si, 4 28 | mov dword [bx+si],0x7c0001ff 29 | ; 0111 1100 0000 0000 0000 0001 1111 1111 30 | ; 线性基地址 15 - 0 0x7c00, 段界限 15 - 0 0x1ff 31 | 32 | add si, 4; 33 | mov dword [bx+si],0x00409800 ; 0000 0000 0100 0000 1001 1000 0000 0000 34 | 35 | ; 0x00; 段基地址 31 - 24 36 | ; 0x4; 37 | ; 0 ; G = 0 粒度字节,段的扩展范围从 1 字节到 1M 字节 (1B - 1MB) 38 | ; G = 1 段界限是以 4KB 为单位 39 | ; 1 ; D/B 默认操作数大小,默认的栈指针大小,上部边界标志; 40 | ; 代码段为 D,用于指示指令中默认的偏移地址和操作数尺寸。 41 | ; D = 0 表示指令中的偏移地址或者操作数是 16 位的 42 | ; D = 1, 指示32位的偏移地址或者操作数。具体的操作影响 使用 ip 还是 eip 43 | ; 对于栈段来说,该位叫做 B 位,影响 sp / esp 44 | ; 位的值也决定了栈的上部边界。如果 B=0, 那么栈段的上部边界(也就是SP 寄存器的最大值)为OxFFFF ; 45 | ; 如果B = 1, 那么栈段的上部边界 (也就是ESP 寄存器的最大值)为OxFFFFFFFF 。 46 | ; 由于这里需要做 32 位保护模式,于是这个值应该一直是 1 47 | ; 0 ; L 64 代码段标志,保留此位给 64 位操作系统使用。目前用不上 48 | ; 0 ; AVL ; 好吧,该安排的都安排了,最后多出这么一位,不知道干什么用好,就给软件用吧 49 | ; 0x0 ; 段界限 19 - 16 50 | 51 | ; 0x9 52 | ; 1 ; P = 1 该段目前在内存中 53 | 54 | ; 00 ; DPL 特权级 0 最高特权级 55 | 56 | ; 1 ; S = 1 属于存储器的段 57 | ; S = 0 表示一个系统段 58 | ; 0x8; 59 | ; 1000 ; Type 表示描述符类型 60 | ; 数据段: 61 | ; X (0 不可执行) 62 | ; E (0 向上扩展,1 向下扩展) 63 | ; W (0 只读,1 可写) 64 | ; A (已访问位,处理器访问时置1,清理由软件负责,用于实现虚拟内存管理) 65 | ; 代码段 66 | ; X(1 可执行) 67 | ; C 68 | ; 0 表示非依从的代码段,这样的代码段可以从与它特权级相同的代码段调用,或者通过门调用; 69 | ; 1 表示允许从低特权级的程序转移到该段执行。 70 | ; R (0 不可读,1 可读),用于限制操作系统和用户,而非CPU 71 | ; A (已访问位,处理器访问时置1,清理由软件负责,用于实现虚拟内存管理) 72 | 73 | ; 0x00 段基地址 23 - 16 74 | 75 | 76 | ;创建#2描述符,保护模式下的数据段描述符(文本模式下的显示缓冲区) 77 | add si, 4; 78 | mov dword [bx+si],0x8000ffff; 线性基地址 15-0 0x8000; 段界限 15 - 0 0xffff; 79 | add si, 4; 80 | mov dword [bx+si],0x0040920b; 100000010010010 00001011 81 | 82 | ; 0x00 ;段基地址 31 - 24 83 | ; 0x40 ; 84 | ; 0x4; 0100 85 | ; 0 ; G 粒度字节 86 | ; 1 ; D/B 32 位标志 87 | ; 0 ; L 88 | ; 0 ; AVL 89 | ; 0x0; 段界限 19 - 16 90 | ; 0x92 ; 91 | ; 0x9 ; 1001 ; 92 | ; 1 ; P 在内存中 93 | ; 00 ; 特权级 0 94 | ; 1 ; S 存储器段 95 | ; 0x2 ; Type 0 数据段 0 向下扩展 1 可写 0 未访问 96 | ; 0x0b ; 段基地址 23 - 16 97 | 98 | ; 线性基地址 0x000b8000 99 | ; 段界限 0x0ffff 100 | 101 | ;创建#3描述符,保护模式下的堆栈段描述符 102 | add si, 4; 103 | mov dword [bx+si],0x00007a00 ; 线性基地址 15-0 0x0000; 段界限 15 - 0 0x7a00; 104 | 105 | add si, 4; 106 | mov dword [bx+si],0x00409600 ; 100000010010110 0000 0000 107 | 108 | ; 0x00 ; 段基地址 31 - 24 109 | ; 0x40 110 | ; 0x4; 0100 111 | ; 0 ; G 粒度字节 112 | ; 1 ; D/B 32 位标志 113 | ; 0 ; L 114 | ; 0 ; AVL 115 | ; 0x0; 段界限 19 - 16 116 | ; 0x96 117 | ; 0x9 ; 1001 ; 118 | ; 1 ; P 在内存中 119 | ; 00 ; 特权级 0 120 | ; 1 ; S 存储器段 121 | ; 0x6 ; Type 0 数据段 1 向上扩展 1 可写 0 未访问 122 | ; 0x00 ; 段基地址 23 - 16 123 | 124 | ; 线性基地址 0x00000000 125 | ; 段界限 0x07a00 126 | 127 | ;初始化描述符表寄存器GDTR 128 | mov word [cs: gdt_size], 31 ;描述符表的界限(总字节数减一) 129 | 130 | ; xchg bx, bx 131 | lgdt [cs: gdt_size] 132 | ; 在这6 字节的内存区域中, 133 | ; 要求前(低) 16 位是GDT 的界限值, 134 | ; 后(高) 32 位是GDT 的基地址。 135 | ; 在初始状态下(计算机启动之后) 136 | ; GDTR 的基地址被初始化为 0x00000000; 界限值为 0xffff 。 137 | 138 | in al,0x92 ;南桥芯片内的端口 139 | or al,0000_0010B 140 | out 0x92,al ;打开A20 141 | 142 | cli ;保护模式下中断机制尚未建立,应 143 | ;禁止中断 144 | mov eax,cr0 145 | or eax,1 146 | mov cr0,eax ;设置PE位 Protection Enable 147 | 148 | ;以下进入保护模式... ... 149 | jmp dword 0x0008:(flush - 0x7c00) ;16位的描述符选择子:32位偏移 150 | ;清流水线并串行化处理器 151 | ; 0000_0000_0000_1000b 152 | 153 | [bits 32] 154 | 155 | flush: 156 | mov cx,0000_0000_00010_0_00B ;加载数据段选择子(10b) 157 | mov ds,cx 158 | 159 | ;以下在屏幕上显示"Protect mode OK." 160 | mov byte [0x00],'P' 161 | mov byte [0x02],'r' 162 | mov byte [0x04],'o' 163 | mov byte [0x06],'t' 164 | mov byte [0x08],'e' 165 | mov byte [0x0a],'c' 166 | mov byte [0x0c],'t' 167 | mov byte [0x0e],' ' 168 | mov byte [0x10],'m' 169 | mov byte [0x12],'o' 170 | mov byte [0x14],'d' 171 | mov byte [0x16],'e' 172 | mov byte [0x18],' ' 173 | mov byte [0x1a],'O' 174 | mov byte [0x1c],'K' 175 | 176 | ;以下用简单的示例来帮助阐述32位保护模式下的堆栈操作 177 | mov cx,00000000000_11_000B ;加载堆栈段选择子 178 | mov ss,cx 179 | mov esp,0x7c00 180 | 181 | mov ebp,esp ;保存堆栈指针 182 | push byte '.' ;压入立即数(字节) 183 | 184 | sub ebp,4 185 | cmp ebp,esp ;判断压入立即数时,ESP是否减4 186 | jnz ghalt 187 | pop eax 188 | mov [0x1e],al ;显示句点 189 | 190 | ghalt: 191 | hlt ;已经禁止中断,将不会被唤醒 192 | 193 | ;------------------------------------------------------------------------------- 194 | 195 | gdt_size dw 0 ; GDT Size - 1 2B 196 | gdt_base dd 0x00007e00 ;GDT的物理地址 4B 197 | 198 | times 510-($-$$) db 0 199 | db 0x55,0xaa -------------------------------------------------------------------------------- /x86/backup/chapter_12.asm: -------------------------------------------------------------------------------- 1 | ;代码清单12-1 2 | ;文件名:c12_mbr.asm 3 | ;文件说明:硬盘主引导扇区代码 4 | ;创建日期:2011-10-27 22:52 5 | 6 | mbr_base equ 0x7c00 7 | 8 | section mbr align=16 vstart=mbr_base 9 | 10 | mov ax, 0x0003; clear screen 11 | int 0x10; 12 | 13 | ;设置堆栈段和栈指针 14 | mov eax,cs 15 | mov ss,eax 16 | mov sp, mbr_base 17 | 18 | ;计算GDT所在的逻辑段地址 19 | mov eax,[cs:gdt+0x02] ;GDT的32位线性基地址 20 | xor edx,edx 21 | mov ebx,16 22 | div ebx ;分解成16位逻辑地址 23 | 24 | mov ds,eax ;令DS指向该段以进行操作 25 | mov ebx,edx ;段内起始偏移地址 26 | 27 | ;创建0#描述符,它是空描述符,这是处理器的要求 28 | mov dword [ebx+0x00],0x00000000 29 | mov dword [ebx+0x04],0x00000000 30 | 31 | ;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间 32 | mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xfffff 33 | mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符 34 | 35 | ;创建保护模式下初始代码段描述符 36 | mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,512字节 37 | mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符 38 | 39 | ;创建以上代码段的别名描述符 40 | mov dword [ebx+0x18],0x7c0001ff ;基地址为0x00007c00,512字节 41 | mov dword [ebx+0x1c],0x00409200 ;粒度为1个字节,数据段描述符 42 | 43 | mov dword [ebx+0x20],0x7c00fffe 44 | mov dword [ebx+0x24],0x00cf9600 45 | 46 | ;初始化描述符表寄存器GDTR 47 | mov word [cs: gdt],39 ;描述符表的界限 48 | 49 | lgdt [cs: gdt] 50 | 51 | in al,0x92 ;南桥芯片内的端口 52 | or al,0000_0010B 53 | out 0x92,al ;打开A20 54 | 55 | cli ;中断机制尚未工作 56 | 57 | mov eax,cr0 58 | or eax,1 59 | mov cr0,eax ;设置PE位 60 | 61 | ;以下进入保护模式... ... 62 | jmp dword 0x0010:(flush - mbr_base) ;16位的描述符选择子:32位偏移 63 | 64 | [bits 32] 65 | flush: 66 | mov eax,0x0018 67 | mov ds,eax 68 | 69 | mov eax,0x0008 ;加载数据段(0..4GB)选择子 70 | mov es,eax 71 | mov fs,eax 72 | mov gs,eax 73 | 74 | mov eax,0x0020 ;0000 0000 0010 0000 75 | mov ss,eax 76 | xor esp,esp ;ESP <- 0 77 | 78 | mov dword [es:0x0b8000],0x072e0750 ;字符'P'、'.'及其显示属性 79 | mov dword [es:0x0b8004],0x072e074d ;字符'M'、'.'及其显示属性 80 | mov dword [es:0x0b8008],0x07200720 ;两个空白字符及其显示属性 81 | mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其显示属性 82 | 83 | xchg bx, bx 84 | ;开始冒泡排序 85 | mov ecx,gdt-string-1 ;遍历次数=串长度-1 86 | @@1: 87 | push ecx ;32位模式下的loop使用ecx 88 | xor bx,bx ;32位模式下,偏移量可以是16位,也可以 89 | @@2: ;是后面的32位 90 | mov ax,[string - mbr_base +bx] 91 | cmp ah,al ;ah中存放的是源字的高字节 92 | jge @@3 93 | xchg al,ah 94 | mov [string - mbr_base +bx],ax 95 | @@3: 96 | inc bx 97 | loop @@2 98 | pop ecx 99 | loop @@1 100 | 101 | mov ecx,gdt-string 102 | xor ebx,ebx ;偏移地址是32位的情况 103 | @@4: ;32位的偏移具有更大的灵活性 104 | mov ah,0x07 105 | mov al,[string - mbr_base +ebx] 106 | mov [es:0xb80a0+ebx*2],ax ;演示0~4GB寻址。 107 | inc ebx 108 | loop @@4 109 | hlt 110 | 111 | ; section data 112 | ;------------------------------------------------------------------------------- 113 | string db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw' 114 | ;------------------------------------------------------------------------------- 115 | gdt dw 0 ; GDT Size 由程序中计算得出 116 | dd 0x00007e00 ;GDT的物理地址 117 | ;------------------------------------------------------------------------------- 118 | times 510-($-$$) db 0 119 | dw 0xaa55 -------------------------------------------------------------------------------- /x86/boot.asm: -------------------------------------------------------------------------------- 1 | ;代码清单13-1 2 | ;文件名:c13_mbr.asm 3 | ;文件说明:硬盘主引导扇区代码 4 | ;创建日期:2011-10-28 22:35 ;设置堆栈段和栈指针 5 | 6 | core_base_address equ 0x00040000 ;常数,内核加载的起始内存地址 7 | core_start_sector equ 0x00000001 ;常数,内核的起始逻辑扇区号 8 | 9 | mov ax, 0x0003; clear screen 10 | int 0x10; 11 | 12 | mov ax,cs 13 | mov ss,ax 14 | mov sp,0x7c00 15 | 16 | ;计算GDT所在的逻辑段地址 17 | mov eax,[cs:pgdt+0x7c00+0x02] ;GDT的32位物理地址 18 | xor edx,edx 19 | mov ebx,16 20 | div ebx ;分解成16位逻辑地址 21 | 22 | mov ds,eax ;令DS指向该段以进行操作 23 | mov ebx,edx ;段内起始偏移地址 24 | 25 | ;跳过0#号描述符的槽位 26 | ;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间 27 | mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xFFFFF 28 | mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符 29 | 30 | ;创建保护模式下初始代码段描述符 31 | mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,界限0x1FF 32 | mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符 33 | 34 | ;建立保护模式下的堆栈段描述符 ;基地址为0x00007C00,界限0xFFFFE 35 | mov dword [ebx+0x18],0x7c00fffe ;粒度为4KB 36 | mov dword [ebx+0x1c],0x00cf9600 37 | 38 | ;建立保护模式下的显示缓冲区描述符 39 | mov dword [ebx+0x20],0x80007fff ;基地址为0x000B8000,界限0x07FFF 40 | mov dword [ebx+0x24],0x0040920b ;粒度为字节 41 | 42 | ;初始化描述符表寄存器GDTR 43 | mov word [cs: pgdt+0x7c00],39 ;描述符表的界限 44 | 45 | lgdt [cs: pgdt+0x7c00] 46 | 47 | in al,0x92 ;南桥芯片内的端口 48 | or al,0000_0010B 49 | out 0x92,al ;打开A20 50 | 51 | cli ;中断机制尚未工作 52 | 53 | mov eax,cr0 54 | or eax,1 55 | mov cr0,eax ;设置PE位 56 | 57 | ;以下进入保护模式... ... 58 | jmp dword 0x0010:flush ;16位的描述符选择子:32位偏移 59 | ;清流水线并串行化处理器 60 | [bits 32] 61 | flush: 62 | mov eax,0x0008 ;加载数据段(0..4GB)选择子 63 | mov ds,eax 64 | 65 | mov eax,0x0018 ;加载堆栈段选择子 66 | mov ss,eax 67 | xor esp,esp ;堆栈指针 <- 0 68 | 69 | ;以下加载系统核心程序 70 | mov edi,core_base_address 71 | 72 | mov eax,core_start_sector 73 | mov ebx,edi ;起始地址 74 | call read_hard_disk_0 ;以下读取程序的起始部分(一个扇区) 75 | 76 | ;以下判断整个程序有多大 77 | mov eax,[edi] ;核心程序尺寸 78 | xor edx,edx 79 | mov ecx,512 ;512字节每扇区 80 | div ecx 81 | 82 | or edx,edx 83 | jnz @1 ;未除尽,因此结果比实际扇区数少1 84 | dec eax ;已经读了一个扇区,扇区总数减1 85 | @1: 86 | or eax,eax ;考虑实际长度≤512个字节的情况 87 | jz setup ;EAX=0 ? 88 | 89 | ;读取剩余的扇区 90 | mov ecx,eax ;32位模式下的LOOP使用ECX 91 | mov eax,core_start_sector 92 | inc eax ;从下一个逻辑扇区接着读 93 | @2: 94 | call read_hard_disk_0 95 | inc eax 96 | loop @2 ;循环读,直到读完整个内核 97 | 98 | setup: 99 | mov esi,[0x7c00+pgdt+0x02] ;不可以在代码段内寻址pgdt,但可以 100 | ;通过4GB的段来访问 101 | ;建立公用例程段描述符 102 | mov eax,[edi+0x04] ;公用例程代码段起始汇编地址 103 | mov ebx,[edi+0x08] ;核心数据段汇编地址 104 | sub ebx,eax 105 | dec ebx ;公用例程段界限 106 | add eax,edi ;公用例程段基地址 107 | mov ecx,0x00409800 ;字节粒度的代码段描述符 108 | call make_gdt_descriptor 109 | mov [esi+0x28],eax 110 | mov [esi+0x2c],edx 111 | 112 | ;建立核心数据段描述符 113 | mov eax,[edi+0x08] ;核心数据段起始汇编地址 114 | mov ebx,[edi+0x0c] ;核心代码段汇编地址 115 | sub ebx,eax 116 | dec ebx ;核心数据段界限 117 | add eax,edi ;核心数据段基地址 118 | mov ecx,0x00409200 ;字节粒度的数据段描述符 119 | call make_gdt_descriptor 120 | mov [esi+0x30],eax 121 | mov [esi+0x34],edx 122 | 123 | ;建立核心代码段描述符 124 | mov eax,[edi+0x0c] ;核心代码段起始汇编地址 125 | mov ebx,[edi+0x00] ;程序总长度 126 | sub ebx,eax 127 | dec ebx ;核心代码段界限 128 | add eax,edi ;核心代码段基地址 129 | mov ecx,0x00409800 ;字节粒度的代码段描述符 130 | call make_gdt_descriptor 131 | mov [esi+0x38],eax 132 | mov [esi+0x3c],edx 133 | 134 | mov word [0x7c00+pgdt],63 ;描述符表的界限 135 | 136 | lgdt [0x7c00+pgdt] 137 | 138 | jmp far [edi+0x10] 139 | 140 | ;------------------------------------------------------------------------------- 141 | read_hard_disk_0: ;从硬盘读取一个逻辑扇区 142 | ;EAX=逻辑扇区号 143 | ;DS:EBX=目标缓冲区地址 144 | ;返回:EBX=EBX+512 145 | push eax 146 | push ecx 147 | push edx 148 | 149 | push eax 150 | 151 | mov dx,0x1f2 152 | mov al,1 153 | out dx,al ;读取的扇区数 154 | 155 | inc dx ;0x1f3 156 | pop eax 157 | out dx,al ;LBA地址7~0 158 | 159 | inc dx ;0x1f4 160 | mov cl,8 161 | shr eax,cl 162 | out dx,al ;LBA地址15~8 163 | 164 | inc dx ;0x1f5 165 | shr eax,cl 166 | out dx,al ;LBA地址23~16 167 | 168 | inc dx ;0x1f6 169 | shr eax,cl 170 | or al,0xe0 ;第一硬盘 LBA地址27~24 171 | out dx,al 172 | 173 | inc dx ;0x1f7 174 | mov al,0x20 ;读命令 175 | out dx,al 176 | 177 | .waits: 178 | in al,dx 179 | and al,0x88 180 | cmp al,0x08 181 | jnz .waits ;不忙,且硬盘已准备好数据传输 182 | 183 | mov ecx,256 ;总共要读取的字数 184 | mov dx,0x1f0 185 | .readw: 186 | in ax,dx 187 | mov [ebx],ax 188 | add ebx,2 189 | loop .readw 190 | 191 | pop edx 192 | pop ecx 193 | pop eax 194 | 195 | ret 196 | 197 | ;------------------------------------------------------------------------------- 198 | make_gdt_descriptor: ;构造描述符 199 | ;输入:EAX=线性基地址 200 | ; EBX=段界限 201 | ; ECX=属性(各属性位都在原始 202 | ; 位置,其它没用到的位置0) 203 | ;返回:EDX:EAX=完整的描述符 204 | mov edx,eax 205 | shl eax,16 206 | or ax,bx ;描述符前32位(EAX)构造完毕 207 | 208 | and edx,0xffff0000 ;清除基地址中无关的位 209 | rol edx,8 210 | bswap edx ;装配基址的31~24和23~16 (80486+) 211 | 212 | xor bx,bx 213 | or edx,ebx ;装配段界限的高4位 214 | 215 | or edx,ecx ;装配属性 216 | 217 | ret 218 | 219 | ;------------------------------------------------------------------------------- 220 | pgdt dw 0 221 | dd 0x00007e00 ;GDT的物理地址 222 | ;------------------------------------------------------------------------------- 223 | times 510-($-$$) db 0 224 | db 0x55,0xaa -------------------------------------------------------------------------------- /x86/build/bochsrc: -------------------------------------------------------------------------------- 1 | # configuration file generated by Bochs 2 | plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, iodebug=true 3 | config_interface: textconfig 4 | display_library: x, options="gui_debug" 5 | memory: host=32, guest=32 6 | romimage: file="/usr/share/bochs/BIOS-bochs-latest", address=0x00000000, options=none 7 | vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest" 8 | boot: disk 9 | floppy_bootsig_check: disabled=0 10 | # no floppya 11 | # no floppyb 12 | ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 13 | ata0-master: type=disk, path="harddisk.img", mode=flat 14 | ata0-slave: type=none 15 | ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15 16 | ata1-master: type=none 17 | ata1-slave: type=none 18 | ata2: enabled=false 19 | ata3: enabled=false 20 | optromimage1: file=none 21 | optromimage2: file=none 22 | optromimage3: file=none 23 | optromimage4: file=none 24 | optramimage1: file=none 25 | optramimage2: file=none 26 | optramimage3: file=none 27 | optramimage4: file=none 28 | pci: enabled=1, chipset=i440fx 29 | vga: extension=vbe, update_freq=5, realtime=1 30 | cpu: count=1:1:1, ips=4000000, quantum=16, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 31 | cpuid: level=6, stepping=3, model=3, family=6, vendor_string="AuthenticAMD", brand_string="AMD Athlon(tm) processor" 32 | cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true 33 | cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, avx_f16c=false 34 | cpuid: avx_fma=false, bmi=0, xop=false, fma4=false, tbm=false, x86_64=true, 1g_pages=false 35 | cpuid: pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true 36 | print_timestamps: enabled=0 37 | debugger_log: - 38 | magic_break: enabled=1 39 | port_e9_hack: enabled=0 40 | private_colormap: enabled=0 41 | clock: sync=none, time0=local, rtc_sync=0 42 | # clock: sync=realtime, time0=local, rtc_sync=1 43 | # no cmosimage 44 | log: - 45 | logprefix: %t%e%d 46 | debug: action=ignore 47 | info: action=report 48 | error: action=report 49 | panic: action=ask 50 | keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none 51 | mouse: type=ps2, enabled=false, toggle=ctrl+mbutton 52 | speaker: enabled=true, mode=system 53 | parport1: enabled=true, file=none 54 | parport2: enabled=false 55 | com1: enabled=true, mode=null 56 | com2: enabled=false 57 | com3: enabled=false 58 | com4: enabled=false 59 | -------------------------------------------------------------------------------- /x86/kernel.asm: -------------------------------------------------------------------------------- 1 | ;代码清单16-1 2 | ;文件名:c16_core.asm 3 | ;文件说明:保护模式微型核心程序 4 | ;创建日期:2012-06-20 00:05 5 | 6 | ;以下常量定义部分。内核的大部分内容都应当固定 7 | core_code_seg_sel equ 0x38 ;内核代码段选择子 8 | core_data_seg_sel equ 0x30 ;内核数据段选择子 9 | sys_routine_seg_sel equ 0x28 ;系统公共例程代码段的选择子 10 | video_ram_seg_sel equ 0x20 ;视频显示缓冲区的段选择子 11 | core_stack_seg_sel equ 0x18 ;内核堆栈段选择子 12 | mem_0_4_gb_seg_sel equ 0x08 ;整个0-4GB内存的段的选择子 13 | 14 | ;------------------------------------------------------------------------------- 15 | ;以下是系统核心的头部,用于加载核心程序 16 | core_length dd core_end ;核心程序总长度#00 17 | 18 | sys_routine_seg dd section.sys_routine.start 19 | ;系统公用例程段位置#04 20 | 21 | core_data_seg dd section.core_data.start 22 | ;核心数据段位置#08 23 | 24 | core_code_seg dd section.core_code.start 25 | ;核心代码段位置#0c 26 | 27 | 28 | core_entry dd start ;核心代码段入口点#10 29 | dw core_code_seg_sel 30 | 31 | ;=============================================================================== 32 | [bits 32] 33 | ;=============================================================================== 34 | SECTION sys_routine vstart=0 ;系统公共例程代码段 35 | ;------------------------------------------------------------------------------- 36 | ;字符串显示例程 37 | put_string: ;显示0终止的字符串并移动光标 38 | ;输入:DS:EBX=串地址 39 | push ecx 40 | .getc: 41 | mov cl,[ebx] 42 | or cl,cl 43 | jz .exit 44 | call put_char 45 | inc ebx 46 | jmp .getc 47 | 48 | .exit: 49 | pop ecx 50 | retf ;段间返回 51 | 52 | ;------------------------------------------------------------------------------- 53 | put_char: ;在当前光标处显示一个字符,并推进 54 | ;光标。仅用于段内调用 55 | ;输入:CL=字符ASCII码 56 | pushad 57 | 58 | ;以下取当前光标位置 59 | mov dx,0x3d4 60 | mov al,0x0e 61 | out dx,al 62 | inc dx ;0x3d5 63 | in al,dx ;高字 64 | mov ah,al 65 | 66 | dec dx ;0x3d4 67 | mov al,0x0f 68 | out dx,al 69 | inc dx ;0x3d5 70 | in al,dx ;低字 71 | mov bx,ax ;BX=代表光标位置的16位数 72 | 73 | cmp cl,0x0d ;回车符? 74 | jnz .put_0a 75 | mov ax,bx 76 | mov bl,80 77 | div bl 78 | mul bl 79 | mov bx,ax 80 | jmp .set_cursor 81 | 82 | .put_0a: 83 | cmp cl,0x0a ;换行符? 84 | jnz .put_other 85 | add bx,80 86 | jmp .roll_screen 87 | 88 | .put_other: ;正常显示字符 89 | push es 90 | mov eax,video_ram_seg_sel ;0x800b8000段的选择子 91 | mov es,eax 92 | shl bx,1 93 | mov [es:bx],cl 94 | pop es 95 | 96 | ;以下将光标位置推进一个字符 97 | shr bx,1 98 | inc bx 99 | 100 | .roll_screen: 101 | cmp bx,2000 ;光标超出屏幕?滚屏 102 | jl .set_cursor 103 | 104 | push ds 105 | push es 106 | mov eax,video_ram_seg_sel 107 | mov ds,eax 108 | mov es,eax 109 | cld 110 | mov esi,0xa0 ;小心!32位模式下movsb/w/d 111 | mov edi,0x00 ;使用的是esi/edi/ecx 112 | mov ecx,1920 113 | rep movsd 114 | mov bx,3840 ;清除屏幕最底一行 115 | mov ecx,80 ;32位程序应该使用ECX 116 | .cls: 117 | mov word[es:bx],0x0720 118 | add bx,2 119 | loop .cls 120 | 121 | pop es 122 | pop ds 123 | 124 | mov bx,1920 125 | 126 | .set_cursor: 127 | mov dx,0x3d4 128 | mov al,0x0e 129 | out dx,al 130 | inc dx ;0x3d5 131 | mov al,bh 132 | out dx,al 133 | dec dx ;0x3d4 134 | mov al,0x0f 135 | out dx,al 136 | inc dx ;0x3d5 137 | mov al,bl 138 | out dx,al 139 | 140 | popad 141 | 142 | ret 143 | 144 | ;------------------------------------------------------------------------------- 145 | read_hard_disk_0: ;从硬盘读取一个逻辑扇区 146 | ;EAX=逻辑扇区号 147 | ;DS:EBX=目标缓冲区地址 148 | ;返回:EBX=EBX+512 149 | push eax 150 | push ecx 151 | push edx 152 | 153 | push eax 154 | 155 | mov dx,0x1f2 156 | mov al,1 157 | out dx,al ;读取的扇区数 158 | 159 | inc dx ;0x1f3 160 | pop eax 161 | out dx,al ;LBA地址7~0 162 | 163 | inc dx ;0x1f4 164 | mov cl,8 165 | shr eax,cl 166 | out dx,al ;LBA地址15~8 167 | 168 | inc dx ;0x1f5 169 | shr eax,cl 170 | out dx,al ;LBA地址23~16 171 | 172 | inc dx ;0x1f6 173 | shr eax,cl 174 | or al,0xe0 ;第一硬盘 LBA地址27~24 175 | out dx,al 176 | 177 | inc dx ;0x1f7 178 | mov al,0x20 ;读命令 179 | out dx,al 180 | 181 | .waits: 182 | in al,dx 183 | and al,0x88 184 | cmp al,0x08 185 | jnz .waits ;不忙,且硬盘已准备好数据传输 186 | 187 | mov ecx,256 ;总共要读取的字数 188 | mov dx,0x1f0 189 | .readw: 190 | in ax,dx 191 | mov [ebx],ax 192 | add ebx,2 193 | loop .readw 194 | 195 | pop edx 196 | pop ecx 197 | pop eax 198 | 199 | retf ;段间返回 200 | 201 | ;------------------------------------------------------------------------------- 202 | ;汇编语言程序是极难一次成功,而且调试非常困难。这个例程可以提供帮助 203 | put_hex_dword: ;在当前光标处以十六进制形式显示 204 | ;一个双字并推进光标 205 | ;输入:EDX=要转换并显示的数字 206 | ;输出:无 207 | pushad 208 | push ds 209 | 210 | mov ax,core_data_seg_sel ;切换到核心数据段 211 | mov ds,ax 212 | 213 | mov ebx,bin_hex ;指向核心数据段内的转换表 214 | mov ecx,8 215 | .xlt: 216 | rol edx,4 217 | mov eax,edx 218 | and eax,0x0000000f 219 | xlat 220 | 221 | push ecx 222 | mov cl,al 223 | call put_char 224 | pop ecx 225 | 226 | loop .xlt 227 | 228 | pop ds 229 | popad 230 | 231 | retf 232 | 233 | ;------------------------------------------------------------------------------- 234 | set_up_gdt_descriptor: ;在GDT内安装一个新的描述符 235 | ;输入:EDX:EAX=描述符 236 | ;输出:CX=描述符的选择子 237 | push eax 238 | push ebx 239 | push edx 240 | 241 | push ds 242 | push es 243 | 244 | mov ebx,core_data_seg_sel ;切换到核心数据段 245 | mov ds,ebx 246 | 247 | sgdt [pgdt] ;以便开始处理GDT 248 | 249 | mov ebx,mem_0_4_gb_seg_sel 250 | mov es,ebx 251 | 252 | movzx ebx,word [pgdt] ;GDT界限 253 | inc bx ;GDT总字节数,也是下一个描述符偏移 254 | add ebx,[pgdt+2] ;下一个描述符的线性地址 255 | 256 | mov [es:ebx],eax 257 | mov [es:ebx+4],edx 258 | 259 | add word [pgdt],8 ;增加一个描述符的大小 260 | 261 | lgdt [pgdt] ;对GDT的更改生效 262 | 263 | mov ax,[pgdt] ;得到GDT界限值 264 | xor dx,dx 265 | mov bx,8 266 | div bx ;除以8,去掉余数 267 | mov cx,ax 268 | shl cx,3 ;将索引号移到正确位置 269 | 270 | pop es 271 | pop ds 272 | 273 | pop edx 274 | pop ebx 275 | pop eax 276 | 277 | retf 278 | ;------------------------------------------------------------------------------- 279 | make_seg_descriptor: ;构造存储器和系统的段描述符 280 | ;输入:EAX=线性基地址 281 | ; EBX=段界限 282 | ; ECX=属性。各属性位都在原始 283 | ; 位置,无关的位清零 284 | ;返回:EDX:EAX=描述符 285 | mov edx,eax 286 | shl eax,16 287 | or ax,bx ;描述符前32位(EAX)构造完毕 288 | 289 | and edx,0xffff0000 ;清除基地址中无关的位 290 | rol edx,8 291 | bswap edx ;装配基址的31~24和23~16 (80486+) 292 | 293 | xor bx,bx 294 | or edx,ebx ;装配段界限的高4位 295 | 296 | or edx,ecx ;装配属性 297 | 298 | retf 299 | 300 | ;------------------------------------------------------------------------------- 301 | make_gate_descriptor: ;构造门的描述符(调用门等) 302 | ;输入:EAX=门代码在段内偏移地址 303 | ; BX=门代码所在段的选择子 304 | ; CX=段类型及属性等(各属 305 | ; 性位都在原始位置) 306 | ;返回:EDX:EAX=完整的描述符 307 | push ebx 308 | push ecx 309 | 310 | mov edx,eax 311 | and edx,0xffff0000 ;得到偏移地址高16位 312 | or dx,cx ;组装属性部分到EDX 313 | 314 | and eax,0x0000ffff ;得到偏移地址低16位 315 | shl ebx,16 316 | or eax,ebx ;组装段选择子部分 317 | 318 | pop ecx 319 | pop ebx 320 | 321 | retf 322 | 323 | ;------------------------------------------------------------------------------- 324 | allocate_a_4k_page: ;分配一个4KB的页 325 | ;输入:无 326 | ;输出:EAX=页的物理地址 327 | push ebx 328 | push ecx 329 | push edx 330 | push ds 331 | 332 | mov eax,core_data_seg_sel 333 | mov ds,eax 334 | 335 | xor eax,eax 336 | .b1: 337 | bts [page_bit_map],eax 338 | jnc .b2 339 | inc eax 340 | cmp eax,page_map_len*8 341 | jl .b1 342 | 343 | mov ebx,message_3 344 | call sys_routine_seg_sel:put_string 345 | hlt ;没有可以分配的页,停机 346 | 347 | .b2: 348 | shl eax,12 ;乘以4096(0x1000) 349 | 350 | pop ds 351 | pop edx 352 | pop ecx 353 | pop ebx 354 | 355 | ret 356 | 357 | ;------------------------------------------------------------------------------- 358 | alloc_inst_a_page: ;分配一个页,并安装在当前活动的 359 | ;层级分页结构中 360 | ;输入:EBX=页的线性地址 361 | push eax 362 | push ebx 363 | push esi 364 | push ds 365 | 366 | mov eax,mem_0_4_gb_seg_sel 367 | mov ds,eax 368 | 369 | ;检查该线性地址所对应的页表是否存在 370 | mov esi,ebx 371 | and esi,0xffc00000 372 | shr esi,20 ;得到页目录索引,并乘以4 373 | or esi,0xfffff000 ;页目录自身的线性地址+表内偏移 374 | 375 | test dword [esi],0x00000001 ;P位是否为“1”。检查该线性地址是 376 | jnz .b1 ;否已经有对应的页表 377 | 378 | ;创建该线性地址所对应的页表 379 | call allocate_a_4k_page ;分配一个页做为页表 380 | or eax,0x00000007 381 | mov [esi],eax ;在页目录中登记该页表 382 | 383 | .b1: 384 | ;开始访问该线性地址所对应的页表 385 | mov esi,ebx 386 | shr esi,10 387 | and esi,0x003ff000 ;或者0xfffff000,因高10位是零 388 | or esi,0xffc00000 ;得到该页表的线性地址 389 | 390 | ;得到该线性地址在页表内的对应条目(页表项) 391 | and ebx,0x003ff000 392 | shr ebx,10 ;相当于右移12位,再乘以4 393 | or esi,ebx ;页表项的线性地址 394 | call allocate_a_4k_page ;分配一个页,这才是要安装的页 395 | or eax,0x00000007 396 | mov [esi],eax 397 | 398 | pop ds 399 | pop esi 400 | pop ebx 401 | pop eax 402 | 403 | retf 404 | 405 | ;------------------------------------------------------------------------------- 406 | create_copy_cur_pdir: ;创建新页目录,并复制当前页目录内容 407 | ;输入:无 408 | ;输出:EAX=新页目录的物理地址 409 | push ds 410 | push es 411 | push esi 412 | push edi 413 | push ebx 414 | push ecx 415 | 416 | mov ebx,mem_0_4_gb_seg_sel 417 | mov ds,ebx 418 | mov es,ebx 419 | 420 | call allocate_a_4k_page 421 | mov ebx,eax 422 | or ebx,0x00000007 423 | mov [0xfffffff8],ebx 424 | 425 | mov esi,0xfffff000 ;ESI->当前页目录的线性地址 426 | mov edi,0xffffe000 ;EDI->新页目录的线性地址 427 | mov ecx,1024 ;ECX=要复制的目录项数 428 | cld 429 | repe movsd 430 | 431 | pop ecx 432 | pop ebx 433 | pop edi 434 | pop esi 435 | pop es 436 | pop ds 437 | 438 | retf 439 | 440 | ;------------------------------------------------------------------------------- 441 | terminate_current_task: ;终止当前任务 442 | ;注意,执行此例程时,当前任务仍在 443 | ;运行中。此例程其实也是当前任务的 444 | ;一部分 445 | mov eax,core_data_seg_sel 446 | mov ds,eax 447 | 448 | pushfd 449 | pop edx 450 | 451 | test dx,0100_0000_0000_0000B ;测试NT位 452 | jnz .b1 ;当前任务是嵌套的,到.b1执行iretd 453 | jmp far [program_man_tss] ;程序管理器任务 454 | .b1: 455 | iretd 456 | 457 | sys_routine_end: 458 | 459 | ;=============================================================================== 460 | SECTION core_data vstart=0 ;系统核心的数据段 461 | ;------------------------------------------------------------------------------- 462 | pgdt dw 0 ;用于设置和修改GDT 463 | dd 0 464 | 465 | page_bit_map db 0xff,0xff,0xff,0xff,0xff,0x55,0x55,0xff 466 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff 467 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff 468 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff 469 | db 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55 470 | db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 471 | db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 472 | db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 473 | page_map_len equ $-page_bit_map 474 | 475 | ;符号地址检索表 476 | salt: 477 | salt_1 db '@PrintString' 478 | times 256-($-salt_1) db 0 479 | dd put_string 480 | dw sys_routine_seg_sel 481 | 482 | salt_2 db '@ReadDiskData' 483 | times 256-($-salt_2) db 0 484 | dd read_hard_disk_0 485 | dw sys_routine_seg_sel 486 | 487 | salt_3 db '@PrintDwordAsHexString' 488 | times 256-($-salt_3) db 0 489 | dd put_hex_dword 490 | dw sys_routine_seg_sel 491 | 492 | salt_4 db '@TerminateProgram' 493 | times 256-($-salt_4) db 0 494 | dd terminate_current_task 495 | dw sys_routine_seg_sel 496 | 497 | salt_item_len equ $-salt_4 498 | salt_items equ ($-salt)/salt_item_len 499 | 500 | message_0 db ' Working in system core,protect mode.' 501 | db 0x0d,0x0a,0 502 | 503 | message_1 db ' Paging is enabled.System core is mapped to' 504 | db ' address 0x80000000.',0x0d,0x0a,0 505 | 506 | message_2 db 0x0d,0x0a 507 | db ' System wide CALL-GATE mounted.',0x0d,0x0a,0 508 | 509 | message_3 db '********No more pages********',0 510 | 511 | message_4 db 0x0d,0x0a,' Task switching...@_@',0x0d,0x0a,0 512 | 513 | message_5 db 0x0d,0x0a,' Processor HALT.',0 514 | 515 | 516 | bin_hex db '0123456789ABCDEF' 517 | ;put_hex_dword子过程用的查找表 518 | 519 | core_buf times 512 db 0 ;内核用的缓冲区 520 | 521 | cpu_brnd0 db 0x0d,0x0a,' ',0 522 | cpu_brand times 52 db 0 523 | cpu_brnd1 db 0x0d,0x0a,0x0d,0x0a,0 524 | 525 | ;任务控制块链 526 | tcb_chain dd 0 527 | 528 | ;内核信息 529 | core_next_laddr dd 0x80100000 ;内核空间中下一个可分配的线性地址 530 | program_man_tss dd 0 ;程序管理器的TSS描述符选择子 531 | dw 0 532 | 533 | core_data_end: 534 | 535 | ;=============================================================================== 536 | SECTION core_code vstart=0 537 | ;------------------------------------------------------------------------------- 538 | fill_descriptor_in_ldt: ;在LDT内安装一个新的描述符 539 | ;输入:EDX:EAX=描述符 540 | ; EBX=TCB基地址 541 | ;输出:CX=描述符的选择子 542 | push eax 543 | push edx 544 | push edi 545 | push ds 546 | 547 | mov ecx,mem_0_4_gb_seg_sel 548 | mov ds,ecx 549 | 550 | mov edi,[ebx+0x0c] ;获得LDT基地址 551 | 552 | xor ecx,ecx 553 | mov cx,[ebx+0x0a] ;获得LDT界限 554 | inc cx ;LDT的总字节数,即新描述符偏移地址 555 | 556 | mov [edi+ecx+0x00],eax 557 | mov [edi+ecx+0x04],edx ;安装描述符 558 | 559 | add cx,8 560 | dec cx ;得到新的LDT界限值 561 | 562 | mov [ebx+0x0a],cx ;更新LDT界限值到TCB 563 | 564 | mov ax,cx 565 | xor dx,dx 566 | mov cx,8 567 | div cx 568 | 569 | mov cx,ax 570 | shl cx,3 ;左移3位,并且 571 | or cx,0000_0000_0000_0100B ;使TI位=1,指向LDT,最后使RPL=00 572 | 573 | pop ds 574 | pop edi 575 | pop edx 576 | pop eax 577 | 578 | ret 579 | 580 | ;------------------------------------------------------------------------------- 581 | load_relocate_program: ;加载并重定位用户程序 582 | ;输入: PUSH 逻辑扇区号 583 | ; PUSH 任务控制块基地址 584 | ;输出:无 585 | pushad 586 | 587 | push ds 588 | push es 589 | 590 | mov ebp,esp ;为访问通过堆栈传递的参数做准备 591 | 592 | mov ecx,mem_0_4_gb_seg_sel 593 | mov es,ecx 594 | 595 | ;清空当前页目录的前半部分(对应低2GB的局部地址空间) 596 | mov ebx,0xfffff000 597 | xor esi,esi 598 | .b1: 599 | mov dword [es:ebx+esi*4],0x00000000 600 | inc esi 601 | cmp esi,512 602 | jl .b1 603 | 604 | ;以下开始分配内存并加载用户程序 605 | mov eax,core_data_seg_sel 606 | mov ds,eax ;切换DS到内核数据段 607 | 608 | mov eax,[ebp+12*4] ;从堆栈中取出用户程序起始扇区号 609 | mov ebx,core_buf ;读取程序头部数据 610 | call sys_routine_seg_sel:read_hard_disk_0 611 | 612 | ;以下判断整个程序有多大 613 | mov eax,[core_buf] ;程序尺寸 614 | mov ebx,eax 615 | and ebx,0xfffff000 ;使之4KB对齐 616 | add ebx,0x1000 617 | test eax,0x00000fff ;程序的大小正好是4KB的倍数吗? 618 | cmovnz eax,ebx ;不是。使用凑整的结果 619 | 620 | mov ecx,eax 621 | shr ecx,12 ;程序占用的总4KB页数 622 | 623 | mov eax,mem_0_4_gb_seg_sel ;切换DS到0-4GB的段 624 | mov ds,eax 625 | 626 | mov eax,[ebp+12*4] ;起始扇区号 627 | mov esi,[ebp+11*4] ;从堆栈中取得TCB的基地址 628 | .b2: 629 | mov ebx,[es:esi+0x06] ;取得可用的线性地址 630 | add dword [es:esi+0x06],0x1000 631 | call sys_routine_seg_sel:alloc_inst_a_page 632 | 633 | push ecx 634 | mov ecx,8 635 | .b3: 636 | call sys_routine_seg_sel:read_hard_disk_0 637 | inc eax 638 | loop .b3 639 | 640 | pop ecx 641 | loop .b2 642 | 643 | ;在内核地址空间内创建用户任务的TSS 644 | mov eax,core_data_seg_sel ;切换DS到内核数据段 645 | mov ds,eax 646 | 647 | mov ebx,[core_next_laddr] ;用户任务的TSS必须在全局空间上分配 648 | call sys_routine_seg_sel:alloc_inst_a_page 649 | add dword [core_next_laddr],4096 650 | 651 | mov [es:esi+0x14],ebx ;在TCB中填写TSS的线性地址 652 | mov word [es:esi+0x12],103 ;在TCB中填写TSS的界限值 653 | 654 | ;在用户任务的局部地址空间内创建LDT 655 | mov ebx,[es:esi+0x06] ;从TCB中取得可用的线性地址 656 | add dword [es:esi+0x06],0x1000 657 | call sys_routine_seg_sel:alloc_inst_a_page 658 | mov [es:esi+0x0c],ebx ;填写LDT线性地址到TCB中 659 | 660 | ;建立程序代码段描述符 661 | mov eax,0x00000000 662 | mov ebx,0x000fffff 663 | mov ecx,0x00c0f800 ;4KB粒度的代码段描述符,特权级3 664 | call sys_routine_seg_sel:make_seg_descriptor 665 | mov ebx,esi ;TCB的基地址 666 | call fill_descriptor_in_ldt 667 | or cx,0000_0000_0000_0011B ;设置选择子的特权级为3 668 | 669 | mov ebx,[es:esi+0x14] ;从TCB中获取TSS的线性地址 670 | mov [es:ebx+76],cx ;填写TSS的CS域 671 | 672 | ;建立程序数据段描述符 673 | mov eax,0x00000000 674 | mov ebx,0x000fffff 675 | mov ecx,0x00c0f200 ;4KB粒度的数据段描述符,特权级3 676 | call sys_routine_seg_sel:make_seg_descriptor 677 | mov ebx,esi ;TCB的基地址 678 | call fill_descriptor_in_ldt 679 | or cx,0000_0000_0000_0011B ;设置选择子的特权级为3 680 | 681 | mov ebx,[es:esi+0x14] ;从TCB中获取TSS的线性地址 682 | mov [es:ebx+84],cx ;填写TSS的DS域 683 | mov [es:ebx+72],cx ;填写TSS的ES域 684 | mov [es:ebx+88],cx ;填写TSS的FS域 685 | mov [es:ebx+92],cx ;填写TSS的GS域 686 | 687 | ;将数据段作为用户任务的3特权级固有堆栈 688 | mov ebx,[es:esi+0x06] ;从TCB中取得可用的线性地址 689 | add dword [es:esi+0x06],0x1000 690 | call sys_routine_seg_sel:alloc_inst_a_page 691 | 692 | mov ebx,[es:esi+0x14] ;从TCB中获取TSS的线性地址 693 | mov [es:ebx+80],cx ;填写TSS的SS域 694 | mov edx,[es:esi+0x06] ;堆栈的高端线性地址 695 | mov [es:ebx+56],edx ;填写TSS的ESP域 696 | 697 | ;在用户任务的局部地址空间内创建0特权级堆栈 698 | mov ebx,[es:esi+0x06] ;从TCB中取得可用的线性地址 699 | add dword [es:esi+0x06],0x1000 700 | call sys_routine_seg_sel:alloc_inst_a_page 701 | 702 | mov eax,0x00000000 703 | mov ebx,0x000fffff 704 | mov ecx,0x00c09200 ;4KB粒度的堆栈段描述符,特权级0 705 | call sys_routine_seg_sel:make_seg_descriptor 706 | mov ebx,esi ;TCB的基地址 707 | call fill_descriptor_in_ldt 708 | or cx,0000_0000_0000_0000B ;设置选择子的特权级为0 709 | 710 | mov ebx,[es:esi+0x14] ;从TCB中获取TSS的线性地址 711 | mov [es:ebx+8],cx ;填写TSS的SS0域 712 | mov edx,[es:esi+0x06] ;堆栈的高端线性地址 713 | mov [es:ebx+4],edx ;填写TSS的ESP0域 714 | 715 | ;在用户任务的局部地址空间内创建1特权级堆栈 716 | mov ebx,[es:esi+0x06] ;从TCB中取得可用的线性地址 717 | add dword [es:esi+0x06],0x1000 718 | call sys_routine_seg_sel:alloc_inst_a_page 719 | 720 | mov eax,0x00000000 721 | mov ebx,0x000fffff 722 | mov ecx,0x00c0b200 ;4KB粒度的堆栈段描述符,特权级1 723 | call sys_routine_seg_sel:make_seg_descriptor 724 | mov ebx,esi ;TCB的基地址 725 | call fill_descriptor_in_ldt 726 | or cx,0000_0000_0000_0001B ;设置选择子的特权级为1 727 | 728 | mov ebx,[es:esi+0x14] ;从TCB中获取TSS的线性地址 729 | mov [es:ebx+16],cx ;填写TSS的SS1域 730 | mov edx,[es:esi+0x06] ;堆栈的高端线性地址 731 | mov [es:ebx+12],edx ;填写TSS的ESP1域 732 | 733 | ;在用户任务的局部地址空间内创建2特权级堆栈 734 | mov ebx,[es:esi+0x06] ;从TCB中取得可用的线性地址 735 | add dword [es:esi+0x06],0x1000 736 | call sys_routine_seg_sel:alloc_inst_a_page 737 | 738 | mov eax,0x00000000 739 | mov ebx,0x000fffff 740 | mov ecx,0x00c0d200 ;4KB粒度的堆栈段描述符,特权级2 741 | call sys_routine_seg_sel:make_seg_descriptor 742 | mov ebx,esi ;TCB的基地址 743 | call fill_descriptor_in_ldt 744 | or cx,0000_0000_0000_0010B ;设置选择子的特权级为2 745 | 746 | mov ebx,[es:esi+0x14] ;从TCB中获取TSS的线性地址 747 | mov [es:ebx+24],cx ;填写TSS的SS2域 748 | mov edx,[es:esi+0x06] ;堆栈的高端线性地址 749 | mov [es:ebx+20],edx ;填写TSS的ESP2域 750 | 751 | 752 | ;重定位SALT 753 | mov eax,mem_0_4_gb_seg_sel ;访问任务的4GB虚拟地址空间时用 754 | mov es,eax 755 | 756 | mov eax,core_data_seg_sel 757 | mov ds,eax 758 | 759 | cld 760 | 761 | mov ecx,[es:0x0c] ;U-SALT条目数 762 | mov edi,[es:0x08] ;U-SALT在4GB空间内的偏移 763 | .b4: 764 | push ecx 765 | push edi 766 | 767 | mov ecx,salt_items 768 | mov esi,salt 769 | .b5: 770 | push edi 771 | push esi 772 | push ecx 773 | 774 | mov ecx,64 ;检索表中,每条目的比较次数 775 | repe cmpsd ;每次比较4字节 776 | jnz .b6 777 | mov eax,[esi] ;若匹配,则esi恰好指向其后的地址 778 | mov [es:edi-256],eax ;将字符串改写成偏移地址 779 | mov ax,[esi+4] 780 | or ax,0000000000000011B ;以用户程序自己的特权级使用调用门 781 | ;故RPL=3 782 | mov [es:edi-252],ax ;回填调用门选择子 783 | .b6: 784 | 785 | pop ecx 786 | pop esi 787 | add esi,salt_item_len 788 | pop edi ;从头比较 789 | loop .b5 790 | 791 | pop edi 792 | add edi,256 793 | pop ecx 794 | loop .b4 795 | 796 | ;在GDT中登记LDT描述符 797 | mov esi,[ebp+11*4] ;从堆栈中取得TCB的基地址 798 | mov eax,[es:esi+0x0c] ;LDT的起始线性地址 799 | movzx ebx,word [es:esi+0x0a] ;LDT段界限 800 | mov ecx,0x00408200 ;LDT描述符,特权级0 801 | call sys_routine_seg_sel:make_seg_descriptor 802 | call sys_routine_seg_sel:set_up_gdt_descriptor 803 | mov [es:esi+0x10],cx ;登记LDT选择子到TCB中 804 | 805 | mov ebx,[es:esi+0x14] ;从TCB中获取TSS的线性地址 806 | mov [es:ebx+96],cx ;填写TSS的LDT域 807 | 808 | mov word [es:ebx+0],0 ;反向链=0 809 | 810 | mov dx,[es:esi+0x12] ;段长度(界限) 811 | mov [es:ebx+102],dx ;填写TSS的I/O位图偏移域 812 | 813 | mov word [es:ebx+100],0 ;T=0 814 | 815 | mov eax,[es:0x04] ;从任务的4GB地址空间获取入口点 816 | mov [es:ebx+32],eax ;填写TSS的EIP域 817 | 818 | pushfd 819 | pop edx 820 | mov [es:ebx+36],edx ;填写TSS的EFLAGS域 821 | 822 | ;在GDT中登记TSS描述符 823 | mov eax,[es:esi+0x14] ;从TCB中获取TSS的起始线性地址 824 | movzx ebx,word [es:esi+0x12] ;段长度(界限) 825 | mov ecx,0x00408900 ;TSS描述符,特权级0 826 | call sys_routine_seg_sel:make_seg_descriptor 827 | call sys_routine_seg_sel:set_up_gdt_descriptor 828 | mov [es:esi+0x18],cx ;登记TSS选择子到TCB 829 | 830 | ;创建用户任务的页目录 831 | ;注意!页的分配和使用是由页位图决定的,可以不占用线性地址空间 832 | call sys_routine_seg_sel:create_copy_cur_pdir 833 | mov ebx,[es:esi+0x14] ;从TCB中获取TSS的线性地址 834 | mov dword [es:ebx+28],eax ;填写TSS的CR3(PDBR)域 835 | 836 | pop es ;恢复到调用此过程前的es段 837 | pop ds ;恢复到调用此过程前的ds段 838 | 839 | popad 840 | 841 | ret 8 ;丢弃调用本过程前压入的参数 842 | 843 | ;------------------------------------------------------------------------------- 844 | append_to_tcb_link: ;在TCB链上追加任务控制块 845 | ;输入:ECX=TCB线性基地址 846 | push eax 847 | push edx 848 | push ds 849 | push es 850 | 851 | mov eax,core_data_seg_sel ;令DS指向内核数据段 852 | mov ds,eax 853 | mov eax,mem_0_4_gb_seg_sel ;令ES指向0..4GB段 854 | mov es,eax 855 | 856 | mov dword [es: ecx+0x00],0 ;当前TCB指针域清零,以指示这是最 857 | ;后一个TCB 858 | 859 | mov eax,[tcb_chain] ;TCB表头指针 860 | or eax,eax ;链表为空? 861 | jz .notcb 862 | 863 | .searc: 864 | mov edx,eax 865 | mov eax,[es: edx+0x00] 866 | or eax,eax 867 | jnz .searc 868 | 869 | mov [es: edx+0x00],ecx 870 | jmp .retpc 871 | 872 | .notcb: 873 | mov [tcb_chain],ecx ;若为空表,直接令表头指针指向TCB 874 | 875 | .retpc: 876 | pop es 877 | pop ds 878 | pop edx 879 | pop eax 880 | 881 | ret 882 | 883 | ;------------------------------------------------------------------------------- 884 | start: 885 | mov ecx,core_data_seg_sel ;令DS指向核心数据段 886 | mov ds,ecx 887 | 888 | mov ecx,mem_0_4_gb_seg_sel ;令ES指向4GB数据段 889 | mov es,ecx 890 | 891 | mov ebx,message_0 892 | call sys_routine_seg_sel:put_string 893 | 894 | ;显示处理器品牌信息 895 | mov eax,0x80000002 896 | cpuid 897 | mov [cpu_brand + 0x00],eax 898 | mov [cpu_brand + 0x04],ebx 899 | mov [cpu_brand + 0x08],ecx 900 | mov [cpu_brand + 0x0c],edx 901 | 902 | mov eax,0x80000003 903 | cpuid 904 | mov [cpu_brand + 0x10],eax 905 | mov [cpu_brand + 0x14],ebx 906 | mov [cpu_brand + 0x18],ecx 907 | mov [cpu_brand + 0x1c],edx 908 | 909 | mov eax,0x80000004 910 | cpuid 911 | mov [cpu_brand + 0x20],eax 912 | mov [cpu_brand + 0x24],ebx 913 | mov [cpu_brand + 0x28],ecx 914 | mov [cpu_brand + 0x2c],edx 915 | 916 | mov ebx,cpu_brnd0 ;显示处理器品牌信息 917 | call sys_routine_seg_sel:put_string 918 | mov ebx,cpu_brand 919 | call sys_routine_seg_sel:put_string 920 | mov ebx,cpu_brnd1 921 | call sys_routine_seg_sel:put_string 922 | 923 | ;准备打开分页机制 924 | 925 | ;创建系统内核的页目录表PDT 926 | ;页目录表清零 927 | mov ecx,1024 ;1024个目录项 928 | mov ebx,0x00020000 ;页目录的物理地址 929 | xor esi,esi 930 | .b1: 931 | mov dword [es:ebx+esi],0x00000000 ;页目录表项清零 932 | add esi,4 933 | loop .b1 934 | 935 | ;在页目录内创建指向页目录自己的目录项 936 | mov dword [es:ebx+4092],0x00020003 937 | 938 | ;在页目录内创建与线性地址0x00000000对应的目录项 939 | mov dword [es:ebx+0],0x00021003 ;写入目录项(页表的物理地址和属性) 940 | 941 | ;创建与上面那个目录项相对应的页表,初始化页表项 942 | mov ebx,0x00021000 ;页表的物理地址 943 | xor eax,eax ;起始页的物理地址 944 | xor esi,esi 945 | .b2: 946 | mov edx,eax 947 | or edx,0x00000003 948 | mov [es:ebx+esi*4],edx ;登记页的物理地址 949 | add eax,0x1000 ;下一个相邻页的物理地址 950 | inc esi 951 | cmp esi,256 ;仅低端1MB内存对应的页才是有效的 952 | jl .b2 953 | 954 | .b3: ;其余的页表项置为无效 955 | mov dword [es:ebx+esi*4],0x00000000 956 | inc esi 957 | cmp esi,1024 958 | jl .b3 959 | 960 | ;令CR3寄存器指向页目录,并正式开启页功能 961 | mov eax,0x00020000 ;PCD=PWT=0 962 | mov cr3,eax 963 | 964 | mov eax,cr0 965 | or eax,0x80000000 966 | mov cr0,eax ;开启分页机制 967 | 968 | ;在页目录内创建与线性地址0x80000000对应的目录项 969 | mov ebx,0xfffff000 ;页目录自己的线性地址 970 | mov esi,0x80000000 ;映射的起始地址 971 | shr esi,22 ;线性地址的高10位是目录索引 972 | shl esi,2 973 | mov dword [es:ebx+esi],0x00021003 ;写入目录项(页表的物理地址和属性) 974 | ;目标单元的线性地址为0xFFFFF200 975 | 976 | ;将GDT中的段描述符映射到线性地址0x80000000 977 | sgdt [pgdt] 978 | 979 | mov ebx,[pgdt+2] 980 | 981 | or dword [es:ebx+0x10+4],0x80000000 982 | or dword [es:ebx+0x18+4],0x80000000 983 | or dword [es:ebx+0x20+4],0x80000000 984 | or dword [es:ebx+0x28+4],0x80000000 985 | or dword [es:ebx+0x30+4],0x80000000 986 | or dword [es:ebx+0x38+4],0x80000000 987 | 988 | add dword [pgdt+2],0x80000000 ;GDTR也用的是线性地址 989 | 990 | lgdt [pgdt] 991 | 992 | jmp core_code_seg_sel:flush ;刷新段寄存器CS,启用高端线性地址 993 | 994 | flush: 995 | mov eax,core_stack_seg_sel 996 | mov ss,eax 997 | 998 | mov eax,core_data_seg_sel 999 | mov ds,eax 1000 | 1001 | mov ebx,message_1 1002 | call sys_routine_seg_sel:put_string 1003 | 1004 | ;以下开始安装为整个系统服务的调用门。特权级之间的控制转移必须使用门 1005 | mov edi,salt ;C-SALT表的起始位置 1006 | mov ecx,salt_items ;C-SALT表的条目数量 1007 | .b4: 1008 | push ecx 1009 | mov eax,[edi+256] ;该条目入口点的32位偏移地址 1010 | mov bx,[edi+260] ;该条目入口点的段选择子 1011 | mov cx,1_11_0_1100_000_00000B ;特权级3的调用门(3以上的特权级才 1012 | ;允许访问),0个参数(因为用寄存器 1013 | ;传递参数,而没有用栈) 1014 | call sys_routine_seg_sel:make_gate_descriptor 1015 | call sys_routine_seg_sel:set_up_gdt_descriptor 1016 | mov [edi+260],cx ;将返回的门描述符选择子回填 1017 | add edi,salt_item_len ;指向下一个C-SALT条目 1018 | pop ecx 1019 | loop .b4 1020 | 1021 | ;对门进行测试 1022 | mov ebx,message_2 1023 | call far [salt_1+256] ;通过门显示信息(偏移量将被忽略) 1024 | 1025 | ;为程序管理器的TSS分配内存空间 1026 | mov ebx,[core_next_laddr] 1027 | call sys_routine_seg_sel:alloc_inst_a_page 1028 | add dword [core_next_laddr],4096 1029 | 1030 | ;在程序管理器的TSS中设置必要的项目 1031 | mov word [es:ebx+0],0 ;反向链=0 1032 | 1033 | mov eax,cr3 1034 | mov dword [es:ebx+28],eax ;登记CR3(PDBR) 1035 | 1036 | mov word [es:ebx+96],0 ;没有LDT。处理器允许没有LDT的任务。 1037 | mov word [es:ebx+100],0 ;T=0 1038 | mov word [es:ebx+102],103 ;没有I/O位图。0特权级事实上不需要。 1039 | 1040 | ;创建程序管理器的TSS描述符,并安装到GDT中 1041 | mov eax,ebx ;TSS的起始线性地址 1042 | mov ebx,103 ;段长度(界限) 1043 | mov ecx,0x00408900 ;TSS描述符,特权级0 1044 | call sys_routine_seg_sel:make_seg_descriptor 1045 | call sys_routine_seg_sel:set_up_gdt_descriptor 1046 | mov [program_man_tss+4],cx ;保存程序管理器的TSS描述符选择子 1047 | 1048 | ;任务寄存器TR中的内容是任务存在的标志,该内容也决定了当前任务是谁。 1049 | ;下面的指令为当前正在执行的0特权级任务“程序管理器”后补手续(TSS)。 1050 | ltr cx 1051 | 1052 | ;现在可认为“程序管理器”任务正执行中 1053 | 1054 | ;创建用户任务的任务控制块 1055 | mov ebx,[core_next_laddr] 1056 | call sys_routine_seg_sel:alloc_inst_a_page 1057 | add dword [core_next_laddr],4096 1058 | 1059 | mov dword [es:ebx+0x06],0 ;用户任务局部空间的分配从0开始。 1060 | mov word [es:ebx+0x0a],0xffff ;登记LDT初始的界限到TCB中 1061 | mov ecx,ebx 1062 | call append_to_tcb_link ;将此TCB添加到TCB链中 1063 | 1064 | push dword 100 ;用户程序位于逻辑50扇区 1065 | push ecx ;压入任务控制块起始线性地址 1066 | 1067 | call load_relocate_program 1068 | 1069 | mov ebx,message_4 1070 | call sys_routine_seg_sel:put_string 1071 | 1072 | call far [es:ecx+0x14] ;执行任务切换。 1073 | 1074 | mov ebx,message_5 1075 | call sys_routine_seg_sel:put_string 1076 | 1077 | hlt 1078 | 1079 | core_code_end: 1080 | 1081 | ;------------------------------------------------------------------------------- 1082 | SECTION core_trail 1083 | ;------------------------------------------------------------------------------- 1084 | core_end: -------------------------------------------------------------------------------- /x86/makefile: -------------------------------------------------------------------------------- 1 | BOOT:= ./boot 2 | BUILD:= ./build 3 | 4 | ASM=nasm 5 | 6 | .PHONY: clean test 7 | 8 | $(BUILD)/boot.bin: boot.asm 9 | $(ASM) $< -o $@ 10 | 11 | $(BUILD)/kernel.bin: kernel.asm 12 | $(ASM) $< -o $@ 13 | 14 | $(BUILD)/app.bin: app.asm 15 | $(ASM) $< -o $@ 16 | 17 | $(BUILD)/test.bin: test.asm 18 | $(ASM) $< -o $@ 19 | 20 | 21 | $(BUILD)/harddisk.img: $(BUILD)/boot.bin $(BUILD)/kernel.bin $(BUILD)/app.bin 22 | ifeq ("$(wildcard $(BUILD)/harddisk.img)", "") 23 | bximage -q -hd=16 -mode=create -sectsize=512 -imgmode=flat $@ 24 | endif 25 | dd if=$(BUILD)/boot.bin of=$@ bs=512 count=1 conv=notrunc 26 | dd if=$(BUILD)/kernel.bin of=$@ bs=512 seek=1 conv=notrunc 27 | dd if=$(BUILD)/app.bin of=$@ bs=512 seek=100 conv=notrunc 28 | 29 | test: $(BUILD)/test.bin 30 | - 31 | 32 | bochs: $(BUILD)/harddisk.img 33 | - 34 | @rm -rf $(BUILD)/harddisk.img.lock 35 | cd $(BUILD) && bochs -q 36 | 37 | clean: 38 | rm -rf $(BUILD)/onix.img 39 | rm -rf $(BUILD)/harddisk.img* 40 | rm -rf $(BUILD)/boot.bin 41 | rm -rf $(BUILD)/kernel.bin 42 | rm -rf $(BUILD)/app.bin 43 | rm -rf $(BUILD)/test.bin 44 | rm -rf $(BUILD)/*.o 45 | rm -rf $(BUILD)/*.a 46 | -------------------------------------------------------------------------------- /x86/test.asm: -------------------------------------------------------------------------------- 1 | section data0 align=16 2 | data1_segment dd section.data1.start 3 | data2_segment dd section.data2.start 4 | data3_segment dd section.data3.start 5 | data4_segment dd section.data4.start 6 | 7 | section data1 align=16 vstart=0 8 | db 0x55 9 | 10 | section data2 align=16 vstart=0 11 | 12 | db 0xaa 13 | 14 | section data3 align=32 vstart=0 15 | dd 0xaa55 16 | 17 | section data4 align=32 vstart=0 18 | dd 0xaa55 -------------------------------------------------------------------------------- /x86/utils/callgate_maker.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | 4 | -------------------------------------------------------------------------------- /x86/utils/gdt_maker.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import ctypes 4 | 5 | 6 | class GDTStructure(ctypes.BigEndianStructure): 7 | 8 | _pack_ = 1 9 | _fields_ = [ 10 | ('base0', ctypes.c_uint16), 11 | ('limit0', ctypes.c_uint16), 12 | ('base2', ctypes.c_uint8), 13 | ('g', ctypes.c_uint8, 1), 14 | ('db', ctypes.c_uint8, 1), 15 | ('l', ctypes.c_uint8, 1), 16 | ('avl', ctypes.c_uint8, 1), 17 | ('limit1', ctypes.c_uint8, 4), 18 | ('p', ctypes.c_uint8, 1), 19 | ('dpl', ctypes.c_uint8, 2), 20 | ('s', ctypes.c_uint8, 1), 21 | ('type', ctypes.c_uint8, 4), 22 | ('base1', ctypes.c_uint8), 23 | ] 24 | 25 | 26 | class GDTMemory(ctypes.BigEndianStructure): 27 | 28 | _pack_ = 1 29 | _fields_ = [ 30 | ('value', ctypes.c_uint64), 31 | ] 32 | 33 | 34 | class GDT(ctypes.Union): 35 | 36 | G_BYTE = 0 37 | G_4K = 1 38 | 39 | DB_16BIT = 0 40 | DB_32BIT = 1 41 | 42 | L_32BIT = 0 43 | L_64BIT = 1 44 | 45 | P_ABSENT = 0 46 | P_EXISTS = 1 47 | 48 | DPL0 = 0 49 | DPL1 = 1 50 | DPL2 = 2 51 | DPL3 = 3 52 | 53 | S_SYSTEM = 0 54 | S_MEMORY = 1 55 | 56 | TYPE_XEWA = None 57 | TYPE_XCRA = None 58 | 59 | _pack_ = 1 60 | _fields_ = [ 61 | ('struct', GDTStructure), 62 | ('byte', GDTMemory), 63 | ] 64 | 65 | def __init__(self): 66 | self.base = 0 67 | self.limit = 0 68 | 69 | def make(self): 70 | self.struct.base0 = self.base & 0xffff 71 | self.struct.base1 = (self.base & 0xff0000) >> 16 72 | self.struct.base2 = (self.base & 0xff000000) >> 24 73 | self.struct.limit0 = self.limit & 0xffff 74 | self.struct.limit1 = (self.limit & 0xf0000) >> 16 75 | 76 | def print(self): 77 | print(self.make()) 78 | 79 | 80 | def main(): 81 | 82 | descripter = GDT() 83 | # descripter = GDTStructure() 84 | # value = 0b10000000_1_1_1_1_0101_1_11_1_1010_00111010 85 | # value = 0b10000000_0_1_0_0_0000_1_00_1_1000_00000000 86 | # value = 0b0_1111111_1_1_1_1 87 | # value = 0x7c0001ff_00409800 88 | # print(bin(value), hex(value)) 89 | # descripter.byte.value = value 90 | 91 | # print("B2 :", hex(descripter.struct.base2)) 92 | # print("B1 :", hex(descripter.struct.base1)) 93 | # print("B0 :", hex(descripter.struct.base0)) 94 | # print("L1 :", hex(descripter.struct.limit1)) 95 | # print("L0 :", hex(descripter.struct.limit0)) 96 | 97 | # print("G :", hex(descripter.struct.g)) 98 | # print("D/B :", hex(descripter.struct.db)) 99 | # print("L :", hex(descripter.struct.l)) 100 | # print("AVL :", hex(descripter.struct.avl)) 101 | # print("P :", hex(descripter.struct.p)) 102 | # print("DPL :", hex(descripter.struct.dpl)) 103 | # print("S :", hex(descripter.struct.s)) 104 | # print("TYPE :", hex(descripter.struct.type)) 105 | 106 | descripter.base = 0x10000 107 | descripter.limit = 0xffff 108 | descripter.struct.g = GDT.G_BYTE 109 | descripter.struct.db = GDT.DB_32BIT 110 | descripter.struct.l = GDT.L_32BIT 111 | descripter.struct.p = GDT.P_EXISTS 112 | descripter.struct.dpl = GDT.DPL0 113 | descripter.struct.s = GDT.S_MEMORY 114 | descripter.struct.type = 0b0010 # GDT.TYPE_XEWA 115 | descripter.make() 116 | 117 | print("GDT :", hex(descripter.byte.value)) 118 | 119 | print(hex(5 << 3 | 0b000)) 120 | 121 | 122 | if __name__ == '__main__': 123 | main() 124 | --------------------------------------------------------------------------------