posts - 2, comments - 3, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

自制os开发记(二)——内核雏形

Posted on 2009-02-25 15:54 bpt 阅读(1150) 评论(1)  编辑 收藏 引用

其实在开学之前已经实现了简单的进程调度,实现了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(0x3d40xe);
 41     outportb(0x3d5, (i >> 8& 0xff);
 42     outportb(0x3d40xf);
 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 *= (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], 00xfffff, DA_CODE32, PRIVILEGE_KERNEL);
 22     fill_segdesc(&gdt[KDATA_SELECTOR >> 3], 00xfffff, DA_DATA32, PRIVILEGE_KERNEL);
 23     fill_segdesc(&gdt[UCODE_SELECTOR >> 3], 00xfffff, DA_CODE32, PRIVILEGE_USER);
 24     fill_segdesc(&gdt[UDATA_SELECTOR >> 3], 00xfffff, 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 = 01++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 = 01++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 = 01++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 = 01++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一下运行的结果:



自己感觉还不错。
目前的kernel仍然很简陋,硬件的初始化尚未完成。异常处理也很简陋,甚至没有考虑到栈的问题。硬件中断也没有完成。
进程调度也没有实现。这些都是下一步的目标。



Feedback

# re: 自制os开发记(二)——内核雏形  回复  更多评论   

2009-02-25 16:08 by 消灭零回复
任务如题

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理