Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html
Linux内核源码分析地址:https://www.cnblogs.com/LexMoon/category/1267413.html
在前几天的任务中,我们已经简单实现了MBR,直接操作显示器和硬盘操作来加载其他扇区的程序,如今已经可以进入保护模式了,之前一直使用的是汇编语言,接下来要使用c语言实现内核了。
0. GCC前提
gcc -c -o main.o main.c
-c的作用是编译,汇编到目标代码,不进行链接,也就是直接生成目标文件。
-o的作用是将输出的文件以指定文件名来存储,有同名文件会直接覆盖。
如果你不会使用GCC,请先去略作了解。
这行命令会生成一个main.o文件。它只是一个目标文件,也是待重定位文件,重定位是指文件里面所用的符号还没有安排地址,这些符号的地址要与其他目标文件组成一个可执行文件时再重新定位(排地址),符号是指该目标文件中所调用的函数或使用的变量,这里的组成就是指链接。
main.o是可重定位文件,ld命令可以链接,指定最终生成文件的起始虚拟地址。
ld main.o -Ttext 0xc0001500 -e main -o main.bin
-Ttext指定了起始虚拟地址是0xc0001500,这个地址是内核加载需要的,-o是指定输出文件,-e是指定了程序起始地址。
1. 引入C语言
内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能,是操作系统工作的基础,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。
现代操作系统设计中,为减少系统本身的开销,往往将一些与硬件紧密相关的(如中断处理程序、设备驱动程序等)、基本的、公共的、运行频率较高的模块(如时钟管理、进程调度等)以及关键性数据结构独立开来,使之常驻内存,并对他们进行保护。通常把这一部分称之为操作系统的内核。
程序可以直接地被调入计算机中执行,这样的设计说明了设计者不希望提供任何硬件抽象和操作系统的支持,它常见于早期计算机系统的设计中。最终,一些辅助性程序,例如程序加载器和调试器,被设计到机器核心当中,或者固化在只读存储器里。这些变化发生时,操作系统内核的概念就渐渐明晰起来了。
antz_os.asm :
1 ; antz_os
2
3
4 BOTPAK EQU 0x00280000
5 DSKCAC EQU 0x00100000
6 DSKCAC0 EQU 0x00008000
7
8
9 CYLS EQU 0x0ff0
10 LEDS EQU 0x0ff1
11 VMODE EQU 0x0ff2
12 SCRNX EQU 0x0ff4
13 SCRNY EQU 0x0ff6
14 VRAM EQU 0x0ff8
15
16 ORG 0xc200
17
18
19
20 MOV AL,0x13
21 MOV AH,0x00
22 INT 0x10
23 MOV BYTE [VMODE],8
24 MOV WORD [SCRNX],320
25 MOV WORD [SCRNY],200
26 MOV DWORD [VRAM],0x000a0000
27
28
29
30 MOV AH,0x02
31 INT 0x16 ; keyboard BIOS
32 MOV [LEDS],AL
33
34
35
36
37
38
39 MOV AL,0xff
40 OUT 0x21,AL
41 NOP
42 OUT 0xa1,AL
43
44 CLI
45
46
47
48 CALL waitkbdout
49 MOV AL,0xd1
50 OUT 0x64,AL
51 CALL waitkbdout
52 MOV AL,0xdf ; enable A20
53 OUT 0x60,AL
54 CALL waitkbdout
55
56 ; 保护模式转换
57
58 [INSTRSET "i486p"]
59
60 LGDT [GDTR0]
61 MOV EAX,CR0
62 AND EAX,0x7fffffff
63 OR EAX,0x00000001
64 MOV CR0,EAX
65 JMP pipelineflush
66
67 MOV AX,1*8
68 MOV DS,AX
69 MOV ES,AX
70 MOV FS,AX
71 MOV GS,AX
72 MOV SS,AX
73
74
75
76 MOV ESI,bootpack ; 源
77 MOV EDI,BOTPAK ; 目标
78 MOV ECX,512*1024/4
79 CALL memcpy
80
81
82
83
84
85 MOV ESI,0x7c00 ; 源
86 MOV EDI,DSKCAC ; 目标
87 MOV ECX,512/4
88 CALL memcpy
89
90
91
92 MOV ESI,DSKCAC0+512 ; 源
93 MOV EDI,DSKCAC+512 ; 目标
94 MOV ECX,0
95 MOV CL,BYTE [CYLS]
96 IMUL ECX,512*18*2/4
97 SUB ECX,512/4
98 CALL memcpy
99
100
101
102
103
104
105 MOV EBX,BOTPAK
106 MOV ECX,[EBX+16]
107 ADD ECX,3
108 SHR ECX,2
109 JZ skip
110 MOV ESI,[EBX+20]
111 ADD ESI,EBX
112 MOV EDI,[EBX+12]
113 CALL memcpy
114 skip:
115 MOV ESP,[EBX+12]
116 JMP DWORD 2*8:0x0000001b
117
118 waitkbdout:
119 IN AL,0x64
120 AND AL,0x02
121 JNZ waitkbdout
122 RET
123
124 memcpy:
125 MOV EAX,[ESI]
126 ADD ESI,4
127 MOV [EDI],EAX
128 ADD EDI,4
129 SUB ECX,1
130 JNZ memcpy
131 RET
132
133
134 ALIGNB 16
135 GDT0:
136 RESB 8
137 DW 0xffff,0x0000,0x9200,0x00cf
138 DW 0xffff,0x0000,0x9a28,0x0047
139 DW 0
140 GDTR0:
141 DW 8*3-1
142 DD GDT0
143
144 ALIGNB 16
145 bootpack:
bootpack.c:
1 void io_hlt(void);
2 void write_mem8(int addr,int data);
3
4 void HariMain(void)
5 {
6 int i ;
7 for(i=0xa0000;i<0xaffff;i++){
8 write_mem8(i,15);
9 }
10 for(;;){
11 io_hlt();
12 }
13 }
func.asm:
1 [FORMAT "WCOFF"]
2 [BITS 32]
3 [INSTRSET "i486p"]
4
5 [FILE "naskfunc.nas"]
6
7 GLOBAL _io_hlt
8
9 [SECTION .text]
10
11 _io_hlt: ; void io_hlt(void);
12 HLT
13 RET
14
15 _write_mem8:
16 MOV ECX,[ESP+4]
17 MOV AL,[ESP+8]
18 MOV [ECX],AL
19 RET
在func.asm中声明了bootpack.c中调用的函数,用于绘制屏幕,如果你还不了解怎么绘制屏幕,可以看看第三天的直接操作显卡部分。
生成的img打开在虚拟机之后。
看到这里你可能会发现,我们在c语言中定义的函数完成了屏幕绘制,在HariMain函数中的for循环将整个屏幕完成了绘制。write_mem8函数的两个参数分别控制了位置和颜色,这是图形化的一大步。
随意修改一下参数之后,屏幕显示就是不一样的颜色了,至于怎么改,可以在for循环里面自行修改了。
关于内核的知识便不再向之前一样详细概况了,推荐一本书,《Linux内核完全剖析》。
来源:oschina
链接:https://my.oschina.net/u/4303671/blog/3282693