其实在开学之前已经实现了简单的进程调度,实现了4个进程轮转。 不过一旦把进程栈调大,进程调度会不稳定,一直找不出原因,再加上代码文件弄的很乱,干脆重写一遍。
回到学校后就转用ubuntu做开发环境了。
目前的代码还是参考了《自》和部分minix的代码,不过《自》中引用的minix代码和《设计与实现》书中的代码不一样,尚不清楚是不是书的版本问题。我的内核实现上有部分细节与参考的代码略有不同,有些地方做了一下省略。目标只是做一个内核的雏形出来。
像minix一样,先贴出几个比较重要的全局头文件。
const.h
1 #ifndef _CONST_H
2 #define _CONST_H
3
4 #define PRIVILEGE_KERNEL (0)
5 #define PRIVILEGE_USER (3)
6
7 #endif
type.h
1 #ifndef _TYPE_H
2 #define _TYPE_H
3
4 #define PUBLIC
5 #define PRIVATE static
6
7 typedef signed char i8_t;
8 typedef signed short i16_t;
9 typedef signed long i32_t;
10 typedef signed long long i64_t;
11
12 typedef unsigned char u8_t;
13 typedef unsigned short u16_t;
14 typedef unsigned long u32_t;
15 typedef unsigned long long u64_t;
16
17 typedef u8_t byte_t;
18 typedef u16_t dbyte_t;
19 typedef u32_t qbyte_t;
20 typedef u64_t obyte_t;
21
22 typedef u32_t address_t;
23
24 #endif
上面两个文件比较简单,今后可以扩充。
接下来是内核用到的头文件。
kconst.h
1 #ifndef _KCONST_H
2 #define _KCONST_H
3
4 #define KCODE_SELECTOR 8
5 #define KDATA_SELECTOR 16
6 #define TSS_SELECTOR 24
7 #define UCODE_SELECTOR (32 + PRIVILEGE_USER)
8 #define UDATA_SELECTOR (40 + PRIVILEGE_USER)
9
10 /* vectors of exception */
11 #define VECTOR_DE 0
12 #define VECTOR_NMI 2
13 #define VECTOR_UD 6
14 #define VECTOR_TS 10
15 #define VECTOR_NP 11
16 #define VECTOR_SS 12
17 #define VECTOR_GP 13
18 #define VECTOR_PF 14
19
20 #define NO_ERROR_CODE 0xffffffff
21
22 /* vectors of hardware int */
23 #define VECTOR_IRQ0 0x20
24 #define VECTOR_IRQ8 0x28
25
26 /* port of 8259 */
27 #define INT_MASTER_CTL 0x20
28 #define INT_MASTER_MASK 0x21
29 #define INT_SLAVE_CTL 0xa0
30 #define INT_SLAVE_MASK 0xa1
31
32 #define NR_TASKS 4
33
34 #endif
global.h
1 #ifndef _GLOBAL_H
2 #define _GLOBAL_H
3
4 #include <type.h>
5 #include "protect.h"
6 #include "process.h"
7
8 #ifdef _GLOBAL_
9 #define EXTERN PUBLIC
10 #else
11 #define EXTERN extern
12 #endif
13
14 EXTERN descriptor_t gdt[8], idt[256], ldt[8];
15
16 EXTERN u64_t gdtr, idtr;
17
18 EXTERN tss_t tss;
19
20 EXTERN byte_t kernel_entered;
21
22 EXTERN process_t proc_table[32];
23
24 EXTERN process_t * ptr_next_proc;
25
26 extern u32_t stack_user;
27
28 #endif
这个头文件要说一下,其中EXTERN宏的用法是学自minix,我这里利用一个测试宏来确定是声明还是定义。
proto.h
1 #ifndef _PROTO_H
2 #define _PROTO_H
3
4 #include "protect.h"
5
6 /* init.c */
7 PUBLIC void init_kernel(void);
8 PUBLIC void init_hardware(void);
9 PUBLIC void fill_segdesc(descriptor_t *desc, address_t base, u32_t limit,
10 dbyte_t attrib, int dpl);
11 PUBLIC void fill_gatedesc(descriptor_t *desc, selector_t seg_selector, address_t offset,
12 byte_t attrib, int dpl);
13
14 /* kernel lib in klib.c & klib.asm */
15 PUBLIC void outportb(int port, byte_t value);
16 PUBLIC void intr_disable(void);
17 PUBLIC void intr_enabla(void);
18 PUBLIC void kputc(char c);
19 PUBLIC void kprintf(char *s,
);
20
21 void default_isr(void);
22
23 /* exception int in kernel.asm */
24 void divide_error(void);
25 void nmi(void);
26 void invalid_opcode(void);
27 void invalid_tss(void);
28 void seg_not_present(void);
29 void stack_fault(void);
30 void general_protection(void);
31 void page_fault(void);
32
33 /* hardware int in kernel.asm */
34 void hwint00(void);
35 void hwint01(void);
36 void hwint02(void);
37 void hwint03(void);
38 void hwint04(void);
39 void hwint05(void);
40 void hwint06(void);
41 void hwint07(void);
42 void hwint08(void);
43 void hwint09(void);
44 void hwint10(void);
45 void hwint11(void);
46 void hwint12(void);
47 void hwint13(void);
48 void hwint14(void);
49 void hwint15(void);
50
51
52 void clock_handler(void);
53
54 #endif
全局头文件的引用,以及这三个头文件的引用按顺序放在kernel.h中。这样写源文件时引用kernel.h即可。
1 #ifndef _KERNEL_H
2 #define _KERNEL_H
3
4 #include <ansi.h>
5 #include <type.h>
6 #include <const.h>
7
8 #include "kconst.h"
9 #include "global.h"
10 #include "proto.h"
11
12 #endif
接下来是两个比较重要的头文件,一个主要包含保护模式需要的类型和常量,另一个主要包含进程调度的类型和常量。
protect.h
1 #ifndef _PROTECT_H
2 #define _PROTECT_H
3
4 #include <type.h>
5
6 typedef u64_t descriptor_t;
7 typedef u16_t selector_t;
8
9 #define DA_CODE32 (0xc098)
10 #define DA_DATA32 (0xc092)
11 #define DA_TSS (0x89)
12 #define DA_LDT (0x82)
13
14 #define GA_INT32 (0x8e)
15
16 typedef struct tss_t {
17 u32_t backlink;
18 u32_t esp0;
19 u32_t ss0;
20 u32_t esp1;
21 u32_t ss1;
22 u32_t esp2;
23 u32_t ss2;
24 u32_t ecr3;
25 u32_t eip;
26 u32_t eflags;
27 u32_t eax;
28 u32_t ecx;
29 u32_t edx;
30 u32_t ebx;
31 u32_t esp;
32 u32_t ebp;
33 u32_t esi;
34 u32_t edi;
35 u32_t es;
36 u32_t cs;
37 u32_t ss;
38 u32_t ds;
39 u32_t fs;
40 u32_t gs;
41 u32_t ldt;
42 u32_t trap;
43 u32_t iobase;
44 } tss_t;
45
46 #endif
东西不多,但都是精心构造好的。
process.h
1 #ifndef _PROCESS_H
2 #define _PROCESS_H
3
4 #include <type.h>
5
6 typedef struct process_t {
7 u32_t gs;
8 u32_t fs;
9 u32_t es;
10 u32_t ds;
11 u32_t edi;
12 u32_t esi;
13 u32_t ebp;
14 u32_t kernel_esp;
15 u32_t ebx;
16 u32_t edx;
17 u32_t ecx;
18 u32_t eax;
19 u32_t ret;
20 u32_t eip;
21 u32_t cs;
22 u32_t eflags;
23 u32_t esp;
24 u32_t ss;
25 u32_t pid;
26 } process_t;
27
28 typedef struct task_t {
29 address_t entry;
30 //u32_t stack_size;
31 //char name[16];
32 } task_t;
33
34 #endif
其中的process_t是进程表项的类型,其中元素的顺序是精心安排好的。ret元素可以说是minix中的一个不错的trick,借助他可以实现不用ret的调用返回。
最后一个头文件是kconst.inc,其中的部分内容要于kconst.h和process.h中的内容同步。
1 %ifndef _KCONST_INC
2 %define _KCONST_INC
3
4
5 %define KCODE_SELECTOR 8
6 %define KDATA_SELECTOR 16
7 %define TSS_SELECTOR 24
8
9 ;vectors of exception
10 %define VECTOR_DE 0
11 %define VECTOR_NMI 2
12 %define VECTOR_UD 6
13 %define VECTOR_TS 10
14 %define VECTOR_NP 11
15 %define VECTOR_SS 12
16 %define VECTOR_GP 13
17 %define VECTOR_PF 14
18
19 %define NO_ERROR_CODE 0xffffffff
20
21 ;vectors of hardware int
22 %define VECTOR_IRQ0 0x20
23 %define VECTOR_IRQ8 0x28
24
25 ;port of 8259
26 %define INT_MASTER_CTL 0x20
27 %define INT_MASTER_MASK 0x21
28 %define INT_SLAVE_CTL 0xa0
29 %define INT_SLAVE_MASK 0xa1
30
31 %define END_OF_INT 0x20
32
33
34 ;process.h
35 PT_GS EQU 0
36 PT_FS EQU PT_GS +4
37 PT_ES EQU PT_FS +4
38 PT_DS EQU PT_ES +4
39 PT_EDI EQU PT_DS +4
40 PT_ESI EQU PT_EDI +4
41 PT_EBP EQU PT_ESI +4
42 PT_KESP EQU PT_EBP +4
43 PT_EBX EQU PT_KESP +4
44 PT_EDX EQU PT_EBX +4
45 PT_ECX EQU PT_EDX +4
46 PT_EAX EQU PT_ECX +4
47 PT_RET EQU PT_EAX +4
48 PT_EIP EQU PT_RET +4
49 PT_CS EQU PT_EIP +4
50 PT_EFLAGS EQU PT_CS +4
51 PT_ESP EQU PT_EFLAGS +4
52 PT_SS EQU PT_ESP +4
53
54 PT_STACK_TOP EQU PT_SS+4
55 TSS_ESP0 EQU 4
56
57 %endif
引用的头文件告一段落,可以看到可执行代码了。现从kernel的入口点开始。
kernel.asm
1 %include "kconst.inc"
2
3 ;=====================================================================
4 ; kernel stack
5 ;=====================================================================
6
7 SECTION .bss
8
9 resb 4 * 1024 ;4KB
10 stack_kernel:
11
12 global stack_user
13 resb 10 * 1024 ;10KB
14 stack_user:
15
16 ;=====================================================================
17 ; kernel
18 ;=====================================================================
19
20 SECTION .text
21
22 extern init_kernel, init_hardware, main
23 extern gdtr, idtr
24 global _start
25 _start:
26 cli
27 mov esp, stack_kernel
28
29 call init_kernel
30 call init_hardware
31
32 cli
33 lgdt [gdtr]
34 lidt [idtr]
35
36 jmp KCODE_SELECTOR:.1
37 .1:
38 mov ax, KDATA_SELECTOR
39 mov ds, ax
40 mov es, ax
41 mov fs, ax
42 mov gs, ax
43 mov ss, ax
44 push 0
45 popf
46
47 mov ax, TSS_SELECTOR
48 ltr ax
49
50 mov al, 0xfe
51 out 0x21, al
52 nop
53 nop
54
55 jmp main
56
57 ;=====================================================================
58 ; default isr
59 ;=====================================================================
60
61 ALIGN 16
62 global default_isr
63 default_isr:
64 cli
65 call save
66 sti
67 call default_handler
68 cli
69 ret
70
71 ;=====================================================================
72 ; exception
73 ;=====================================================================
74
75 ;+++++++++++++++++++++++++++++++++++++++++++++++++
76 ; EH_ERR label, vector, error
77 ;+++++++++++++++++++++++++++++++++++++++++++++++++
78
79 %macro EH_ERR 2
80 ALIGN 16
81 global %1
82 %1:
83 push %2
84 jmp exception
85 %endmacro
86
87 ;+++++++++++++++++++++++++++++++++++++++++++++++++
88 ; EH_NOERR lable, vector
89 ;+++++++++++++++++++++++++++++++++++++++++++++++++
90
91 %macro EH_NOERR 2
92 ALIGN 16
93 global %1
94 %1:
95 push NO_ERROR_CODE
96 push %2
97 jmp exception
98 %endmacro
99
100 ;+++++++++++++++++++++++++++++++++++++++++++++++++
101 ;+++++++++++++++++++++++++++++++++++++++++++++++++
102
103 EH_NOERR divide_error, VECTOR_DE
104 EH_NOERR nmi, VECTOR_NMI
105 EH_NOERR invalid_opcode, VECTOR_UD
106 EH_ERR invalid_tss, VECTOR_TS
107 EH_ERR seg_not_present, VECTOR_NP
108 EH_ERR stack_fault, VECTOR_SS
109 EH_ERR general_protection, VECTOR_GP
110 EH_ERR page_fault, VECTOR_PF
111
112 ALIGN 16
113 exception:
114 extern exception_handler
115 call exception_handler
116 add esp, 8
117 hlt
118 jmp $
119 iretd
120
121 ;%unmacro EH_NOERR 2
122 ;%unmacro EH_ERR 2
123
124
125 ;=====================================================================
126 ; hardware int
127 ;=====================================================================
128
129 ;+++++++++++++++++++++++++++++++++++++++++++++++++
130 ; HWINT_MASTER label, irq, handler
131 ;+++++++++++++++++++++++++++++++++++++++++++++++++
132
133 %macro HWINT_MASTER 3
134 ALIGN 16
135 global %1
136 %1:
137 call save
138 in al, INT_MASTER_MASK
139 or al, (1 << %2)
140 out INT_MASTER_MASK, al
141 mov al, END_OF_INT
142 out INT_MASTER_CTL, al
143 sti
144 call %3
145 cli
146 in al, INT_MASTER_MASK
147 and al, ~(1 << %2)
148 out INT_MASTER_MASK, al
149 ret
150 %endmacro
151
152 ;+++++++++++++++++++++++++++++++++++++++++++++++++
153 ; HWINT_SLAVE label, irq, handler
154 ;+++++++++++++++++++++++++++++++++++++++++++++++++
155
156 %macro HWINT_SLAVE 3
157 ALIGN 16
158 global %1
159 %1:
160 call save
161 in al, INT_SLAVE_MASK
162 or al, (1 << (%2 - 8))
163 out INT_SLAVE_MASK, al
164 mov al, END_OF_INT
165 out INT_SLAVE_CTL, al
166 sti
167 call %3
168 cli
169 in al, INT_SLAVE_MASK
170 and al, ~(1 << (%2 - 8))
171 out INT_SLAVE_MASK, al
172 ret
173 %endmacro
174
175 ;+++++++++++++++++++++++++++++++++++++++++++++++++
176 ;+++++++++++++++++++++++++++++++++++++++++++++++++
177
178 extern clock_handler
179
180 HWINT_MASTER hwint00, 0, clock_handler
181 HWINT_MASTER hwint01, 1, default_handler
182 HWINT_MASTER hwint02, 2, default_handler
183 HWINT_MASTER hwint03, 3, default_handler
184 HWINT_MASTER hwint04, 4, default_handler
185 HWINT_MASTER hwint05, 5, default_handler
186 HWINT_MASTER hwint06, 6, default_handler
187 HWINT_MASTER hwint07, 7, default_handler
188
189 HWINT_SLAVE hwint08, 8, default_handler
190 HWINT_SLAVE hwint09, 9, default_handler
191 HWINT_SLAVE hwint10, 10, default_handler
192 HWINT_SLAVE hwint11, 11, default_handler
193 HWINT_SLAVE hwint12, 12, default_handler
194 HWINT_SLAVE hwint13, 13, default_handler
195 HWINT_SLAVE hwint14, 14, default_handler
196 HWINT_SLAVE hwint15, 15, default_handler
197
198
199 ;=====================================================================
200 ; save
201 ;=====================================================================
202
203 ALIGN 16
204 extern kernel_entered
205 save:
206 pushad
207 push ds
208 push es
209 push fs
210 push gs
211 mov ebp, esp
212 cmp byte [kernel_entered], 0
213 jne .reenter
214 inc byte [kernel_entered]
215 mov esp, stack_kernel
216 push restart
217 inc byte [0xb8002]
218 jmp [ebp + PT_RET]
219 ALIGN 16
220 .reenter:
221 push restart.1
222 inc byte [0xb8004]
223 jmp [ebp + PT_RET]
224
225 ;=====================================================================
226 ; restart
227 ;=====================================================================
228
229 ALIGN 16
230 extern ptr_next_proc, tss
231 global restart:
232 restart:
233 mov esp, dword [ptr_next_proc]
234 lea eax, [esp + PT_STACK_TOP]
235 mov dword [tss + TSS_ESP0], eax
236 dec byte [kernel_entered]
237 .1:
238 pop gs
239 pop fs
240 pop es
241 pop ds
242 popad
243 add esp, 4
244 iretd
245
246
247
248
249 ALIGN 16
250 extern kprintf
251 default_handler:
252 push .msg
253 call kprintf
254 add esp, 4
255 hlt
256 jmp $
257 ret
258
259 ALIGN 4
260 .msg DB `int handler not completed yet!\n`, 0
261
事实上这个kernel还很粗糙,比如save为了调试而改变显存的值,以及那个default_handler。IRQ0打开的也很粗暴。好在架构已经成形,剩下的是细节部分的打磨。
global.c是全局变量的所在地。呵呵,真是脱了global.h的福。
1 #define _GLOBAL_
2 #include "global.h"
再有就是一个简单的库,klib.c和klib.asm里面有个非常简陋的输出函数,主要拿来调试用的。
1 #include "kernel.h"
2
3 PUBLIC void kputc(char c)
4 {
5 static int pos = 160, row = 1, col = 0;
6 int i;
7
8 if (24 == row) {
9
10 for (i = 0xb8000; i < 0xb8000 + 24 * 160; i += 2) {
11 *(dbyte_t *)i = *(dbyte_t *)(i + 160);
12 }
13 --row;
14 pos -= 160;
15 /*
16 --row;
17 start += 80;
18 outportb(0x3d4, 0xc);
19 outportb(0x3d5, (start >> 8) & 0xff);
20 outportb(0x3d4, 0xd);
21 outportb(0x3d5, start & 0xff);
22 */
23 }
24 switch (c) {
25 case '\n':
26 ++row;
27 col = 0;
28 pos = row * 160;
29 break;
30 default:
31 *(dbyte_t *)(0xb8000 + pos) = (dbyte_t)0x700 | c;
32 pos += 2;
33 ++col;
34 if (80 == col) {
35 ++row;
36 col = 0;
37 }
38 }
39 i = (pos >> 1);
40 outportb(0x3d4, 0xe);
41 outportb(0x3d5, (i >> 8) & 0xff);
42 outportb(0x3d4, 0xf);
43 outportb(0x3d5, i & 0xff);
44 return;
45 }
46
47 PRIVATE void kprint_hex(unsigned int x);
48 PRIVATE void kprint_int(int x);
49
50 PUBLIC void kprintf(char * s,
)
51 {
52 u32_t * ptr_arg = (u32_t *)(&s);
53
54 while (*s) {
55 if ('%' == *s) {
56 ++s;
57 switch (*s) {
58 case 'x':
59 ++s;
60 ++ptr_arg;
61 kputc('0');
62 kputc('x');
63 kprint_hex(*ptr_arg);
64 break;
65 case 'd':
66 ++s;
67 ++ptr_arg;
68 kprint_int(*ptr_arg);
69 break;
70 default:
71 kputc('%');
72 }
73 } else {
74 kputc(*s);
75 ++s;
76 }
77 }
78 return;
79 }
80
81 PRIVATE void kprint_hex(unsigned int x)
82 {
83 int i;
84
85 if (0 == x) {
86 kputc('0');
87 return;
88 }
89 for (i = 4; i < 32; i += 4) {
90 if ((x >> i) == 0) {
91 break;
92 }
93 }
94 for (i -= 4; i >= 0; i -= 4) {
95 kputc("0123456789abcdef"[(x >> i) & 0xf]);
96 }
97 return;
98 }
99
100 PRIVATE void _kprint_int(int x);
101
102 PRIVATE void kprint_int(int x)
103 {
104 if (0 == x) {
105 kputc('0');
106 } else if (x > 0) {
107 _kprint_int(x);
108 } else {
109 kputc('-');
110 _kprint_int(-x);
111 }
112 return;
113 }
114
115 PRIVATE void _kprint_int(int x)
116 {
117 if (x) {
118 _kprint_int(x /10);
119 kputc("01234567890"[x % 10]);
120 }
121 return;
122 }
1 SECTION .text
2
3 ;=====================================================================
4 ; void outportb(dbyte_t port, byte_t value)
5 ;=====================================================================
6
7 global outportb
8 outportb:
9 push edx
10
11 mov dx, word [esp + 8]
12 mov al, byte [esp + 12]
13 out dx, al
14 nop
15 nop
16
17 pop edx
18 ret
19
20 ;=====================================================================
21 ; void intr_disable(void)
22 ;=====================================================================
23
24 global intr_disable
25 intr_disable:
26 cli
27 ret
28
29 ;=====================================================================
30 ; void intr_enable(void)
31 ;=====================================================================
32
33 global intr_enable
34 intr_enable:
35 sti
36 ret
继续,下面是init.c。
1 #include "kernel.h"
2 #include "protect.h"
3 #include "process.h"
4
5 /*====================================================================*
6 * init_kernel *
7 *====================================================================*/
8
9 PUBLIC void init_kernel(void)
10 {
11 int i;
12
13 byte_t *p = (byte_t *)(&gdtr);
14 *(u16_t *)(p + 0) = (u16_t)(sizeof(gdt) - 1);
15 *(u32_t *)(p + 2) = (u32_t)(&gdt);
16
17 p = (byte_t *)(&idtr);
18 *(u16_t *)(p + 0) = (u16_t)(sizeof(idt) - 1);
19 *(u32_t *)(p + 2) = (u32_t)(&idt);
20
21 fill_segdesc(&gdt[KCODE_SELECTOR >> 3], 0, 0xfffff, DA_CODE32, PRIVILEGE_KERNEL);
22 fill_segdesc(&gdt[KDATA_SELECTOR >> 3], 0, 0xfffff, DA_DATA32, PRIVILEGE_KERNEL);
23 fill_segdesc(&gdt[UCODE_SELECTOR >> 3], 0, 0xfffff, DA_CODE32, PRIVILEGE_USER);
24 fill_segdesc(&gdt[UDATA_SELECTOR >> 3], 0, 0xfffff, DA_DATA32, PRIVILEGE_USER);
25
26 tss.ss0 = KDATA_SELECTOR;
27 tss.iobase = sizeof(tss);
28 fill_segdesc(&gdt[TSS_SELECTOR >> 3], (address_t)(&tss), sizeof(tss) - 1,
29 DA_TSS, PRIVILEGE_KERNEL);
30
31 struct isr_table_t {
32 address_t entry;
33 int privilege;
34 } isr_table[256];
35
36 #define ISR_TABLE(V,E,P) {isr_table[V].entry = (address_t)(E); \
37 isr_table[V].privilege = (P);}
38
39 for (i = 0; i < 256; ++i) {
40 ISR_TABLE(i, default_isr, PRIVILEGE_USER);
41 }
42
43 ISR_TABLE(VECTOR_DE, divide_error, PRIVILEGE_KERNEL);
44 ISR_TABLE(VECTOR_NMI, nmi, PRIVILEGE_KERNEL);
45 ISR_TABLE(VECTOR_UD, invalid_opcode, PRIVILEGE_KERNEL);
46 ISR_TABLE(VECTOR_TS, invalid_tss, PRIVILEGE_KERNEL);
47 ISR_TABLE(VECTOR_NP, seg_not_present, PRIVILEGE_KERNEL);
48 ISR_TABLE(VECTOR_SS, stack_fault, PRIVILEGE_KERNEL);
49 ISR_TABLE(VECTOR_GP, general_protection, PRIVILEGE_KERNEL);
50 ISR_TABLE(VECTOR_PF, page_fault, PRIVILEGE_KERNEL);
51
52 ISR_TABLE(VECTOR_IRQ0, hwint00, PRIVILEGE_KERNEL);
53 ISR_TABLE(VECTOR_IRQ0 + 1, hwint01, PRIVILEGE_KERNEL);
54 ISR_TABLE(VECTOR_IRQ0 + 2, hwint02, PRIVILEGE_KERNEL);
55 ISR_TABLE(VECTOR_IRQ0 + 3, hwint03, PRIVILEGE_KERNEL);
56 ISR_TABLE(VECTOR_IRQ0 + 4, hwint04, PRIVILEGE_KERNEL);
57 ISR_TABLE(VECTOR_IRQ0 + 5, hwint05, PRIVILEGE_KERNEL);
58 ISR_TABLE(VECTOR_IRQ0 + 6, hwint06, PRIVILEGE_KERNEL);
59 ISR_TABLE(VECTOR_IRQ0 + 7, hwint07, PRIVILEGE_KERNEL);
60 ISR_TABLE(VECTOR_IRQ8, hwint08, PRIVILEGE_KERNEL);
61 ISR_TABLE(VECTOR_IRQ8 + 1, hwint09, PRIVILEGE_KERNEL);
62 ISR_TABLE(VECTOR_IRQ8 + 2, hwint10, PRIVILEGE_KERNEL);
63 ISR_TABLE(VECTOR_IRQ8 + 3, hwint11, PRIVILEGE_KERNEL);
64 ISR_TABLE(VECTOR_IRQ8 + 4, hwint12, PRIVILEGE_KERNEL);
65 ISR_TABLE(VECTOR_IRQ8 + 5, hwint13, PRIVILEGE_KERNEL);
66 ISR_TABLE(VECTOR_IRQ8 + 6, hwint14, PRIVILEGE_KERNEL);
67 ISR_TABLE(VECTOR_IRQ8 + 7, hwint15, PRIVILEGE_KERNEL);
68
69 for (i = 0; i < 256; ++i) {
70 fill_gatedesc(&idt[i], KCODE_SELECTOR, isr_table[i].entry,
71 GA_INT32, isr_table[i].privilege);
72 }
73
74 return;
75 }
76
77
78 /*====================================================================*
79 * fill_segdesc *
80 *====================================================================*/
81
82 PUBLIC void fill_segdesc(descriptor_t *desc, address_t base, u32_t limit,
83 dbyte_t attrib, int dpl)
84 {
85 address_t p = (address_t)desc;
86
87 *(dbyte_t *)(p + 0) = limit & 0xffff;
88 *(dbyte_t *)(p + 2) = base & 0xffff;
89 *(byte_t *)(p + 4) = (base >> 16) & 0xff;
90 *(dbyte_t *)(p + 5) = attrib | ((limit >> 8) & 0xf00) | (dpl << 5);
91 *(byte_t *)(p + 7) = (base >> 24) & 0xff;
92 return;
93 }
94
95 /*====================================================================*
96 * fill_gatedesc *
97 *====================================================================*/
98
99 PUBLIC void fill_gatedesc(descriptor_t *desc, selector_t seg_selector,
100 address_t offset, byte_t attrib, int dpl)
101 {
102 address_t p = (address_t)desc;
103
104 *(dbyte_t *)(p + 0) = offset & 0xffff;
105 *(dbyte_t *)(p + 2) = seg_selector;
106 *(byte_t *)(p + 4) = 0;
107 *(byte_t *)(p + 5) = attrib | (dpl << 5);
108 *(dbyte_t *)(p + 6) = (offset >> 16) & 0xffff;
109 return;
110 }
111
112 /*====================================================================*
113 * init_hardware *
114 *====================================================================*/
115
116 PUBLIC void init_hardware(void)
117 {
118 //init_8253();
119 init_8259();
120 return;
121 }
其中对8253的初始化尚未实现,留作下一个目标。
8259.c
1 #include "kernel.h"
2
3 /*====================================================================*
4 * init_8259 *
5 *====================================================================*/
6
7 PUBLIC void init_8259(void)
8 {
9 intr_disable();
10
11 /* master ICW1 */
12 outportb(INT_MASTER_CTL, 0x11);
13
14 /* master ICW2 */
15 outportb(INT_MASTER_MASK, VECTOR_IRQ0);
16
17 /* master ICW3 */
18 outportb(INT_MASTER_MASK, (1 << 2));
19
20 /* master ICW4 */
21 outportb(INT_MASTER_MASK, 0x1);
22
23 /* master OCW1 , IRQ0 ~ IRQ7 mask */
24 outportb(INT_MASTER_MASK, ~(1 << 2));
25
26 /* slave ICW1 */
27 outportb(INT_SLAVE_CTL, 0x11);
28
29 /* slave ICW2 */
30 outportb(INT_SLAVE_MASK, VECTOR_IRQ8);
31
32 /* slave ICW3 */
33 outportb(INT_SLAVE_MASK, 2);
34
35 /* slave ICW4 */
36 outportb(INT_SLAVE_MASK, 0x1);
37
38 /* slave OCW1 , IRQ8 ~ IRQ15 mask */
39 outportb(INT_SLAVE_MASK, ~0);
40
41 return;
42 }
exception.c,异常处理函数
1 #include "kernel.h"
2
3 void exception_handler(int vector, int err_code)
4 {
5 u32_t * p;
6
7 static char msg[20][50] = {
8 "Divide 0",
9 "",
10 "",
11 "",
12 "",
13 "",
14 "Undefined Opcode",
15 "",
16 "",
17 "",
18 "Invalid TTS",
19 "Segment Not Present",
20 "Stack-Segment Fault",
21 "General Protection",
22 "Page Fault",
23 "",
24 "",
25 "Alignment Check",
26 };
27
28 kprintf("\n\n====================================================\n\n");
29 kprintf("An exception here!\n");
30 kprintf(msg[vector]);
31 kprintf(", error code is %x\n", err_code);
32
33 if (err_code & 0x2) {
34 p = (u32_t *)(&idt[(err_code & 0xffff) >> 3]);
35 kprintf("vector of this gate is %x\n", (err_code & 0xffff) >> 3);
36 kprintf("gate decriptor in ldt is %x(high) %x(low)\n\n", *(p + 1), *p);
37 } else {
38 p = (u32_t *)(&gdt[(err_code & 0xffff) >> 3]);
39 kprintf("seg decriptor in gdt is %x(high) %x(low)\n\n", *(p + 1), *p);
40 }
41 return;
42 }
clock.c,时钟任务,仅仅作轮转调度,有待扩充
1 #include "kernel.h"
2
3 PUBLIC void clock_handler(void)
4 {
5 //++(*(byte_t *)0xb8000);
6
7 ++ptr_next_proc;
8 if (proc_table + NR_TASKS == ptr_next_proc) {
9 ptr_next_proc = &proc_table[0];
10 }
11 return;
12 }
main.c,由内核级下降到用户级,启动第一个进程
1 #include "kernel.h"
2
3 void TestA(void);
4 void TestB(void);
5 void TestC(void);
6 void TestD(void);
7
8 int main(void)
9 {
10 static task_t task_table[NR_TASKS] = {
11 { (address_t)TestA },
12 { (address_t)TestB },
13 { (address_t)TestC },
14 { (address_t)TestD },
15 };
16 address_t stack_top = (address_t)&stack_user;
17 process_t *p;
18 int i;
19
20 for (i = 0; i < NR_TASKS; ++i) {
21 p = &proc_table[i];
22 p->cs = UCODE_SELECTOR;
23 p->ds =
24 p->es =
25 p->fs =
26 p->gs =
27 p->ss = UDATA_SELECTOR;
28 p->esp = (u32_t)stack_top;
29 p->eip = (u32_t)task_table[i].entry;
30 p->eflags = 0x3202;
31
32 stack_top -= 2048;
33 }
34
35 kernel_entered = 1;
36 ptr_next_proc = &proc_table[0];
37 kprintf("start first process\n");
38 restart();
39 return 0;
40 }
41
test.c,其中有四个测试进程
1 #include "kernel.h"
2
3 PRIVATE void delay(void);
4
5 void TestA(void)
6 {
7 int i;
8
9 for (i = 0; 1; ++i) {
10 kprintf("A%d ", i);
11 delay();
12 }
13 return;
14 }
15
16 void TestB(void)
17 {
18 int i;
19
20 for (i = 0; 1; ++i) {
21 kprintf("B%d ", i);
22 delay();
23 }
24 return;
25 }
26
27 void TestC(void)
28 {
29 int i;
30
31 for (i = 0; 1; ++i) {
32 kprintf("C%d ", i);
33 delay();
34 }
35 return;
36 }
37
38 void TestD(void)
39 {
40 int i;
41
42 for (i = 0; 1; ++i) {
43 kprintf("D%d ", i);
44 delay();
45 }
46 return;
47 }
48
49 PRIVATE void delay(void)
50 {
51 int i, j;
52
53 for (i = 0; i < 1000000; ++i) {
54 ++j;
55 }
56 }
好,最后贴上编译用的Makefile,编译后就可以在virtualbox上看到结果了。
1 ENTRYPOINT = 0x30400
2 HEADERS = kernel.h global.h kconst.h proto.h protect.h process.h
3
4 AS = nasm
5 ASFLAGS = -f elf
6 CC = gcc
7 CFLAGS = -c -I ../include
8 LD = ld
9 LDFLAGS = -s -Ttext $(ENTRYPOINT)
10
11 OBJS = kernel.o global.o init.o 8259.o main.o klib1.o klib2.o exception.o clock.o test.o
12
13 kernel.bin: $(OBJS)
14 $(LD) $(LDFLAGS) -o $@ $(OBJS)
15 rm -f $(OBJS)
16 sudo mount ../TINIX.IMG /mnt/TINIX -o loop
17 sudo cp -f $@ /mnt/TINIX
18 sudo umount /mnt/TINIX
19 rm $@
20
21 kernel.o: kernel.asm kconst.inc
22 $(AS) $(ASFLAGS) -o $@ $<
23
24 global.o: global.c $(HEADERS)
25 $(CC) $(CFLAGS) -o $@ $<
26
27 init.o: init.c $(HEADERS)
28 $(CC) $(CFLAGS) -o $@ $<
29
30 8259.o: 8259.c $(HEADERS)
31 $(CC) $(CFLAGS) -o $@ $<
32
33 main.o: main.c $(HEADERS)
34 $(CC) $(CFLAGS) -o $@ $<
35
36 klib1.o: klib.c $(HEADERS)
37 $(CC) $(CFLAGS) -o $@ $<
38
39 klib2.o: klib.asm kconst.inc
40 $(AS) $(ASFLAGS) -o $@ $<
41
42 exception.o: exception.c $(HEADERS)
43 $(CC) $(CFLAGS) -o $@ $<
44
45 clock.o: clock.c $(HEADERS)
46 $(CC) $(CFLAGS) -o $@ $<
47
48 test.o: test.c $(HEADERS)
49 $(CC) $(CFLAGS) -o $@ $<
50
51 unmount:
52 sudo umount /mnt/TINIX
show一下运行的结果:
![](http://www.cppblog.com/images/cppblog_com/bpt/kernel.jpg)
自己感觉还不错。
目前的kernel仍然很简陋,硬件的初始化尚未完成。异常处理也很简陋,甚至没有考虑到栈的问题。硬件中断也没有完成。
进程调度也没有实现。这些都是下一步的目标。