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


其实在开学之前已经实现了简单的进程调度,实现了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  * =  (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一下运行的结果:
自制os开发记(二)——内核雏形_第1张图片


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



你可能感兴趣的:(自制os开发记(二)——内核雏形)