跳到主要內容

遲到的處理序-第一個處理序

處理序


  • 宏觀:有自己的目標或功能,且又受控於處理序調度模組(就是老闆啦!)
  • 微觀:利用系統資源、有自己的程式碼和資料,與自己的堆疊;需要被調度,就如一個人輪換著做不同工作
處理序示意圖

未雨綢繆

未來會有多個處理序,但 CPU 只有一個,亦即 CPU 通常小於處理序個數:同一時刻,總有「正在執行的」與「正在休息的」處理序。對於「正在休息的」處理序,我們必須讓它在重新醒來時記住自己掛起前的狀態,以便讓原來的任務繼續執行下去。

因此,我們需要一個資料結構紀錄一個處理序的狀態:在處理序要被掛起的時候,處理序資料被寫入這個資料結構,等到處理序重新開機時,這個資訊重新被讀出來。
資料結構,用以紀錄處理序的狀態

最簡單的處理序

  1. 處理序A執行中
  2. 時鐘中斷發生,ring1 -> ring0,時鐘中斷處理常式啟動
  3. 處理序調度,下一個應執行的處理序(假設為處理序B)被指定
  4. 處理序B被恢復,ring1 -> ring0
  5. 處理序B執行中

程式碼

include/const.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef    _ORANGES_CONST_H_
#define    _ORANGES_CONST_H_


/* EXTERN */
#define    EXTERN    extern     /* EXTERN is defined as extern except in global.c */

/* 函数类型 */
#define    PUBLIC               /* PUBLIC is the opposite of PRIVATE */
#define    PRIVATE    static    /* PRIVATE x limits the scope of x */

/* Boolean */
#define    TRUE        1
#define    FALSE    0

/* GDT 和 IDT 中描述符的个数 */
#define    GDT_SIZE    128
#define    IDT_SIZE    256

/* 权限 */
#define    PRIVILEGE_KRNL    0
#define    PRIVILEGE_TASK    1
#define    PRIVILEGE_USER    3
/* RPL */
#define    RPL_KRNL    SA_RPL0
#define    RPL_TASK    SA_RPL1
#define    RPL_USER    SA_RPL3

/* 8259A interrupt controller ports. */
#define    INT_M_CTL    0x20        /* I/O port for interrupt controller         <Master> */
#define    INT_M_CTLMASK    0x21    /* setting bits in this port disables ints   <Master> */
#define    INT_S_CTL    0xA0        /* I/O port for second interrupt controller  <Slave>  */
#define    INT_S_CTLMASK    0xA1    /* setting bits in this port disables ints   <Slave>  */


#endif /* _ORANGES_CONST_H_ */

include/global.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            global.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/* EXTERN is defined as extern except in global.c */
#ifdef    GLOBAL_VARIABLES_HERE
#undef    EXTERN
#define    EXTERN
#endif

EXTERN    int           disp_pos;
EXTERN    u8            gdt_ptr[6];    // 0~15:Limit  16~47:Base
EXTERN    DESCRIPTOR    gdt[GDT_SIZE];
EXTERN    u8            idt_ptr[6];    // 0~15:Limit  16~47:Base
EXTERN    GATE          idt[IDT_SIZE];

EXTERN    TSS           tss;
EXTERN    PROCESS*      p_proc_ready;

extern    PROCESS       proc_table[];
extern    char          task_stack[];

include/proc.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                               proc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/


typedef struct s_stackframe {
    u32    gs;         /* \                                    */
    u32    fs;         /* |                                    */
    u32    es;         /* |                                    */
    u32    ds;         /* |                                    */
    u32    edi;        /* |                                    */
    u32    esi;        /* | pushed by save()                   */
    u32    ebp;        /* |                                    */
    u32    kernel_esp; /* <- 'popad' will ignore it            */
    u32    ebx;        /* |                                    */
    u32    edx;        /* |                                    */
    u32    ecx;        /* |                                    */
    u32    eax;        /* /                                    */
    u32    retaddr;    /* return addr for kernel.asm::save()   */
    u32    eip;        /* \                                    */
    u32    cs;         /* |                                    */
    u32    eflags;     /* | pushed by CPU during interrupt     */
    u32    esp;        /* |                                    */
    u32    ss;         /* /                                    */
}STACK_FRAME;


typedef struct s_proc {
    STACK_FRAME regs;          /* process registers saved in stack frame */

    u16 ldt_sel;               /* gdt selector giving ldt base and limit */
    DESCRIPTOR ldts[LDT_SIZE]; /* local descriptors for code and data */
    u32 pid;                   /* process id passed in from MM */
    char p_name[16];           /* name of the process */
}PROCESS;


/* Number of tasks */
#define NR_TASKS    1

/* stacks of tasks */
#define STACK_SIZE_TESTA    0x8000

#define STACK_SIZE_TOTAL    STACK_SIZE_TESTA

include/protect.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            protect.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef    _ORANGES_PROTECT_H_
#define    _ORANGES_PROTECT_H_


/* 存儲段描述符/系統段描述符 */
typedef struct s_descriptor /* 共 8 個字節 */
{
    u16    limit_low;       /* Limit */
    u16    base_low;        /* Base */
    u8    base_mid;         /* Base */
    u8    attr1;            /* P(1) DPL(2) DT(1) TYPE(4) */
    u8    limit_high_attr2; /* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */
    u8    base_high;        /* Base */
}DESCRIPTOR;

/* 門描述符 */
typedef struct s_gate
{
    u16    offset_low;      /* Offset Low */
    u16    selector;        /* Selector */
    u8     dcount;          /* 該字段只在調用門描述符中有效。
                               如果在利用調用門調用子程序時引起特權級的轉換和堆棧的改變,需要將外層堆棧中的參數複製到內層堆棧。
                               該雙字計數字段就是用於說明這種情況發生時,要複製的雙字參數的數量。 */
    u8     attr;            /* P(1) DPL(2) DT(1) TYPE(4) */
    u16    offset_high;     /* Offset High */
}GATE;

typedef struct s_tss {
    u32    backlink;
    u32    esp0;    /* stack pointer to use during interrupt */
    u32    ss0;     /*   "   segment  "  "    "        "     */
    u32    esp1;
    u32    ss1;
    u32    esp2;
    u32    ss2;
    u32    cr3;
    u32    eip;
    u32    flags;
    u32    eax;
    u32    ecx;
    u32    edx;
    u32    ebx;
    u32    esp;
    u32    ebp;
    u32    esi;
    u32    edi;
    u32    es;
    u32    cs;
    u32    ss;
    u32    ds;
    u32    fs;
    u32    gs;
    u32    ldt;
    u16    trap;
    u16    iobase;    /* I/O位圖基址大於或等於TSS段界限,就表示沒有I/O許可位圖 */
}TSS;

/* GDT */
/* 描述符索引 */
#define    INDEX_DUMMY      0    /* \                         */
#define    INDEX_FLAT_C     1    /* | LOADER 裡面已經確定了的 */
#define    INDEX_FLAT_RW    2    /* |                         */
#define    INDEX_VIDEO      3    /* /                         */
#define    INDEX_TSS        4
#define    INDEX_LDT_FIRST  5
/* 選擇子 */
#define    SELECTOR_DUMMY       0           /* \                         */
#define    SELECTOR_FLAT_C      0x08        /* | LOADER 裡面已經確定了的 */
#define    SELECTOR_FLAT_RW     0x10        /* |                         */
#define    SELECTOR_VIDEO       (0x18+3)    /* /<-- RPL=3             */
#define    SELECTOR_TSS         0x20        /* TSS                       */
#define SELECTOR_LDT_FIRST      0x28

#define    SELECTOR_KERNEL_CS    SELECTOR_FLAT_C
#define    SELECTOR_KERNEL_DS    SELECTOR_FLAT_RW
#define    SELECTOR_KERNEL_GS    SELECTOR_VIDEO

/* 每個任務有一個單獨的 LDT, 每個 LDT 中的描述符個數: */
#define LDT_SIZE        2

/* 選擇子類型值說明 */
/* 其中, SA_ : Selector Attribute */
#define    SA_RPL_MASK    0xFFFC
#define    SA_RPL0        0
#define    SA_RPL1        1
#define    SA_RPL2        2
#define    SA_RPL3        3

#define    SA_TI_MASK    0xFFFB
#define    SA_TIG        0
#define    SA_TIL        4

/* 描述符類型值說明 */
#define    DA_32              0x4000    /* 32 位段                */
#define    DA_LIMIT_4K        0x8000    /* 段界限粒度為 4K 字節   */
#define    DA_DPL0            0x00      /* DPL = 0                */
#define    DA_DPL1            0x20      /* DPL = 1                */
#define    DA_DPL2            0x40      /* DPL = 2                */
#define    DA_DPL3            0x60      /* DPL = 3                */
/* 存儲段描述符類型值說明 */
#define    DA_DR           0x90    /* 存在的只讀數據段類型值           */
#define    DA_DRW          0x92    /* 存在的可讀寫數據段屬性值         */
#define    DA_DRWA         0x93    /* 存在的已訪問可讀寫數據段類型值   */
#define    DA_C            0x98    /* 存在的只執行代碼段屬性值         */
#define    DA_CR           0x9A    /* 存在的可執行可讀代碼段屬性值     */
#define    DA_CCO          0x9C    /* 存在的只執行一致代碼段屬性值     */
#define    DA_CCOR         0x9E    /* 存在的可執行可讀一致代碼段屬性值 */
/* 系統段描述符類型值說明 */
#define    DA_LDT           0x82    /* 局部描述符表段類型值        */
#define    DA_TaskGate      0x85    /* 任務門類型值                */
#define    DA_386TSS        0x89    /* 可用 386 任務狀態段類型值   */
#define    DA_386CGate      0x8C    /* 386 調用門類型值            */
#define    DA_386IGate      0x8E    /* 386 中斷門類型值            */
#define    DA_386TGate      0x8F    /* 386 陷阱門類型值            */

/* 中斷向量 */
#define    INT_VECTOR_DIVIDE            0x0
#define    INT_VECTOR_DEBUG             0x1
#define    INT_VECTOR_NMI               0x2
#define    INT_VECTOR_BREAKPOINT        0x3
#define    INT_VECTOR_OVERFLOW          0x4
#define    INT_VECTOR_BOUNDS            0x5
#define    INT_VECTOR_INVAL_OP          0x6
#define    INT_VECTOR_COPROC_NOT        0x7
#define    INT_VECTOR_DOUBLE_FAULT      0x8
#define    INT_VECTOR_COPROC_SEG        0x9
#define    INT_VECTOR_INVAL_TSS         0xA
#define    INT_VECTOR_SEG_NOT           0xB
#define    INT_VECTOR_STACK_FAULT       0xC
#define    INT_VECTOR_PROTECTION        0xD
#define    INT_VECTOR_PAGE_FAULT        0xE
#define    INT_VECTOR_COPROC_ERR        0x10

/* 中斷向量 */
#define    INT_VECTOR_IRQ0            0x20
#define    INT_VECTOR_IRQ8            0x28


/* 宏 */
/* 線性地址 → 物理地址 */
#define vir2phys(seg_base, vir)    (u32)(((u32)seg_base) + (u32)(vir))


#endif /* _ORANGES_PROTECT_H_ */

include/proto.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            proto.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/* klib.asm */
PUBLIC void    out_byte(u16 port, u8 value);
PUBLIC u8      in_byte(u16 port);
PUBLIC void    disp_str(char * info);
PUBLIC void    disp_color_str(char * info, int color);

/* protect.c */
PUBLIC void   init_prot();
PUBLIC u32    seg2phys(u16 seg);

/* klib.c */
PUBLIC void    delay(int time);

/* kernel.asm */
void restart();

/* main.c */
void TestA();

include/sconst.inc

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                               sconst.inc
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                                                     Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

P_STACKBASE    equ    0
GSREG        equ    P_STACKBASE
FSREG        equ    GSREG        + 4
ESREG        equ    FSREG        + 4
DSREG        equ    ESREG        + 4
EDIREG       equ    DSREG        + 4
ESIREG       equ    EDIREG       + 4
EBPREG       equ    ESIREG       + 4
KERNELESPREG equ    EBPREG       + 4
EBXREG       equ    KERNELESPREG + 4
EDXREG       equ    EBXREG       + 4
ECXREG       equ    EDXREG       + 4
EAXREG       equ    ECXREG       + 4
RETADR       equ    EAXREG       + 4
EIPREG       equ    RETADR       + 4
CSREG        equ    EIPREG       + 4
EFLAGSREG    equ    CSREG        + 4
ESPREG       equ    EFLAGSREG    + 4
SSREG        equ    ESPREG       + 4
P_STACKTOP   equ    SSREG        + 4
P_LDT_SEL    equ    P_STACKTOP
P_LDT        equ    P_LDT_SEL    + 4

TSS3_S_SP0   equ    4

; 以下選擇子值必須與 protect.h 中保持一致!!!
SELECTOR_FLAT_C     equ        0x08    ; LOADER 裡面已經確定了的.
SELECTOR_TSS        equ        0x20    ; TSS
SELECTOR_KERNEL_CS  equ        SELECTOR_FLAT_C

include/string.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            string.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

PUBLIC    void*   memcpy(void* p_dst, void* p_src, int size);
PUBLIC    void    memset(void* p_dst, char ch, int size);

include/type.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            type.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef    _ORANGES_TYPE_H_
#define    _ORANGES_TYPE_H_


typedef    unsigned int        u32;
typedef    unsigned short      u16;
typedef    unsigned char       u8;


typedef    void    (*int_handler)    ();


#endif /* _ORANGES_TYPE_H_ */

kernel/global.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            global.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#define GLOBAL_VARIABLES_HERE

#include "type.h"
#include "const.h"
#include "protect.h"
#include "proto.h"
#include "proc.h"
#include "global.h"


PUBLIC    PROCESS         proc_table[NR_TASKS];

PUBLIC    char            task_stack[STACK_SIZE_TOTAL];

kernel/i8259.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            i8259.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/


#include "type.h"
#include "const.h"
#include "protect.h"
#include "proto.h"


/*======================================================================*
                            init_8259A
 *======================================================================*/
PUBLIC void init_8259A()
{
    out_byte(INT_M_CTL,        0x11);               // Master 8259, ICW1.
    out_byte(INT_S_CTL,        0x11);               // Slave  8259, ICW1.
    out_byte(INT_M_CTLMASK,    INT_VECTOR_IRQ0);    // Master 8259, ICW2. 設置 '主8259' 的中斷入口地址為 0x20.
    out_byte(INT_S_CTLMASK,    INT_VECTOR_IRQ8);    // Slave  8259, ICW2. 設置 '從8259' 的中斷入口地址為 0x28
    out_byte(INT_M_CTLMASK,    0x4);                // Master 8259, ICW3. IR2 對應 '從8259'.
    out_byte(INT_S_CTLMASK,    0x2);                // Slave  8259, ICW3. 對應 '主8259' 的 IR2.
    out_byte(INT_M_CTLMASK,    0x1);                // Master 8259, ICW4.
    out_byte(INT_S_CTLMASK,    0x1);                // Slave  8259, ICW4.

    out_byte(INT_M_CTLMASK,    0xFF);               // Master 8259, OCW1.
    out_byte(INT_S_CTLMASK,    0xFF);               // Slave  8259, OCW1.
}

/*======================================================================*
                           spurious_irq
 *======================================================================*/
PUBLIC void spurious_irq(int irq)
{
    disp_str("spurious_irq: ");
    disp_int(irq);
    disp_str("\n");
}

kernel/kernel.asm

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                               kernel.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                                                     Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


%include "sconst.inc"

; 導入函數
extern    cstart
extern    kernel_main
extern    exception_handler
extern    spurious_irq

; 導入全局變量
extern    gdt_ptr
extern    idt_ptr
extern    p_proc_ready
extern    tss
extern    disp_pos

bits 32

[SECTION .bss]
StackSpace        resb    2 * 1024
StackTop:        ; 堆疊頂

[section .text]  ; 程式碼在此

global _start    ; 導出 _start

global restart

global    divide_error
global    single_step_exception
global    nmi
global    breakpoint_exception
global    overflow
global    bounds_check
global    inval_opcode
global    copr_not_available
global    double_fault
global    copr_seg_overrun
global    inval_tss
global    segment_not_present
global    stack_exception
global    general_protection
global    page_fault
global    copr_error
global    hwint00
global    hwint01
global    hwint02
global    hwint03
global    hwint04
global    hwint05
global    hwint06
global    hwint07
global    hwint08
global    hwint09
global    hwint10
global    hwint11
global    hwint12
global    hwint13
global    hwint14
global    hwint15


_start:
    ; 此時記憶體看上去是這樣的(更詳細的記憶體情況在 LOADER.ASM 中有說明):
    ;              ┃                            ┃
    ;              ┃                 ...        ┃
    ;              ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■■■ Page  Tables   ■■■■■■┃
    ;              ┃■■■■■ (大小由LOADER決定)■■■■┃ PageTblBase
    ;    00101000h ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■Page Directory Table■■■■┃ PageDirBase = 1M
    ;    00100000h ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃□□□□ Hardware  Reserved □□□□┃ B8000h ← gs
    ;       9FC00h ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■■■■  LOADER.BIN   ■■■■■■┃ somewhere in LOADER ← esp
    ;       90000h ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■■■■  KERNEL.BIN   ■■■■■■┃
    ;       80000h ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃■■■■■■■■  KERNEL     ■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr)
    ;       30000h ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┋                 ...        ┋
    ;              ┋                            ┋
    ;           0h ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss
    ;
    ;
    ; GDT 以及相應的描述符是這樣的:
    ;
    ;                      Descriptors               Selectors
    ;              ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
    ;              ┃         Dummy Descriptor           ┃
    ;              ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃         DESC_FLAT_C    (0~4G)     ┃   8h = cs
    ;              ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃         DESC_FLAT_RW   (0~4G)     ┃  10h = ds, es, fs, ss
    ;              ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ;              ┃         DESC_VIDEO                 ┃  1Bh = gs
    ;              ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
    ;
    ; 注意! 在使用 C 程式碼的時候一定要保證 ds, es, ss 這幾個段暫存器的值是一樣的
    ; 因為編譯器有可能編譯出使用它們的程式碼, 而編譯器默認它們是一樣的. 比如串拷貝操作會用到 ds 和 es.
    ;
    ;


    ; 把 esp 從 LOADER 挪到 KERNEL
    mov     esp, StackTop    ; 堆疊在 bss 段中

    mov     dword [disp_pos], 0

    sgdt    [gdt_ptr]    ; cstart() 中將會用到 gdt_ptr
    call    cstart        ; 在此函數中改變了gdt_ptr,讓它指向新的GDT
    lgdt    [gdt_ptr]    ; 使用新的GDT

    lidt    [idt_ptr]

    jmp     SELECTOR_KERNEL_CS:csinit
csinit:     ; “這個跳轉指令強制使用剛剛初始化的結構”——<<OS:D&I 2nd>> P90.

    ;jmp    0x40:0
    ;ud2


    xor     eax, eax
    mov     ax, SELECTOR_TSS
    ltr     ax

    ;sti
    jmp     kernel_main

    ;hlt


; 中斷和異常 -- 硬件中斷
; ---------------------------------
%macro     hwint_master    1
    push   %1
    call   spurious_irq
    add    esp, 4
    hlt
%endmacro


ALIGN    16
hwint00:        ; Interrupt routine for irq 0 (the clock).
    iretd

ALIGN    16
hwint01:        ; Interrupt routine for irq 1 (keyboard)
    hwint_master    1

ALIGN    16
hwint02:        ; Interrupt routine for irq 2 (cascade!)
    hwint_master    2

ALIGN    16
hwint03:        ; Interrupt routine for irq 3 (second serial)
    hwint_master    3

ALIGN    16
hwint04:        ; Interrupt routine for irq 4 (first serial)
    hwint_master    4

ALIGN    16
hwint05:        ; Interrupt routine for irq 5 (XT winchester)
    hwint_master    5

ALIGN    16
hwint06:        ; Interrupt routine for irq 6 (floppy)
    hwint_master    6

ALIGN    16
hwint07:        ; Interrupt routine for irq 7 (printer)
    hwint_master    7

; ---------------------------------
%macro     hwint_slave    1
    push   %1
    call   spurious_irq
    add    esp, 4
    hlt
%endmacro
; ---------------------------------

ALIGN    16
hwint08:        ; Interrupt routine for irq 8 (realtime clock).
    hwint_slave    8

ALIGN    16
hwint09:        ; Interrupt routine for irq 9 (irq 2 redirected)
    hwint_slave    9

ALIGN    16
hwint10:        ; Interrupt routine for irq 10
    hwint_slave    10

ALIGN    16
hwint11:        ; Interrupt routine for irq 11
    hwint_slave    11

ALIGN    16
hwint12:        ; Interrupt routine for irq 12
    hwint_slave    12

ALIGN    16
hwint13:        ; Interrupt routine for irq 13 (FPU exception)
    hwint_slave    13

ALIGN    16
hwint14:        ; Interrupt routine for irq 14 (AT winchester)
    hwint_slave    14

ALIGN    16
hwint15:        ; Interrupt routine for irq 15
    hwint_slave    15



; 中斷和異常 -- 異常
divide_error:
    push    0xFFFFFFFF    ; no err code
    push    0             ; vector_no    = 0
    jmp    exception
single_step_exception:
    push    0xFFFFFFFF    ; no err code
    push    1             ; vector_no    = 1
    jmp    exception
nmi:
    push    0xFFFFFFFF    ; no err code
    push    2             ; vector_no    = 2
    jmp    exception
breakpoint_exception:
    push    0xFFFFFFFF    ; no err code
    push    3             ; vector_no    = 3
    jmp    exception
overflow:
    push    0xFFFFFFFF    ; no err code
    push    4             ; vector_no    = 4
    jmp    exception
bounds_check:
    push    0xFFFFFFFF    ; no err code
    push    5             ; vector_no    = 5
    jmp    exception
inval_opcode:
    push    0xFFFFFFFF    ; no err code
    push    6             ; vector_no    = 6
    jmp    exception
copr_not_available:
    push    0xFFFFFFFF    ; no err code
    push    7             ; vector_no    = 7
    jmp    exception
double_fault:
    push    8             ; vector_no    = 8
    jmp    exception
copr_seg_overrun:
    push    0xFFFFFFFF    ; no err code
    push    9             ; vector_no    = 9
    jmp    exception
inval_tss:
    push    10            ; vector_no    = A
    jmp    exception
segment_not_present:
    push    11            ; vector_no    = B
    jmp    exception
stack_exception:
    push    12            ; vector_no    = C
    jmp    exception
general_protection:
    push    13            ; vector_no    = D
    jmp    exception
page_fault:
    push    14            ; vector_no    = E
    jmp    exception
copr_error:
    push    0xFFFFFFFF    ; no err code
    push    16            ; vector_no    = 10h
    jmp    exception

exception:
    call    exception_handler
    add    esp, 4*2    ; 讓堆疊頂指向 EIP,堆疊中從頂向下依次是:EIP、CS、EFLAGS
    hlt


; ====================================================================================
;                                   restart
; ====================================================================================
restart:
    mov    esp, [p_proc_ready]
    lldt   [esp + P_LDT_SEL]
    lea    eax, [esp + P_STACKTOP]
    mov    dword [tss + TSS3_S_SP0], eax

    pop    gs
    pop    fs
    pop    es
    pop    ds
    popad

    add    esp, 4

    iretd

kernel/main.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "proto.h"
#include "string.h"
#include "proc.h"
#include "global.h"


/*======================================================================*
                            kernel_main
 *======================================================================*/
PUBLIC int kernel_main()
{
    disp_str("-----\"kernel_main\" begins-----\n");

    PROCESS* p_proc    = proc_table;

    p_proc->ldt_sel    = SELECTOR_LDT_FIRST;
    memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS>>3], sizeof(DESCRIPTOR));
    p_proc->ldts[0].attr1 = DA_C | PRIVILEGE_TASK << 5;    // change the DPL
    memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS>>3], sizeof(DESCRIPTOR));
    p_proc->ldts[1].attr1 = DA_DRW | PRIVILEGE_TASK << 5;    // change the DPL

    p_proc->regs.cs    = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc->regs.ds    = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc->regs.es    = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc->regs.fs    = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc->regs.ss    = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc->regs.gs    = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | RPL_TASK;
    p_proc->regs.eip= (u32)TestA;
    p_proc->regs.esp= (u32) task_stack + STACK_SIZE_TOTAL;
    p_proc->regs.eflags = 0x1202;    // IF=1, IOPL=1, bit 2 is always 1.

    p_proc_ready    = proc_table;
    restart();

    while(1){}
}

/*======================================================================*
                               TestA
 *======================================================================*/
void TestA()
{
    int i = 0;
    while(1){
        disp_str("A");
        disp_int(i++);
        disp_str(".");
        delay(1);
    }
}

kernel/protect.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                              protect.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "proto.h"
#include "proc.h"
#include "global.h"


/* 本文件內函數聲明 */
PRIVATE void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege);
PRIVATE void init_descriptor(DESCRIPTOR * p_desc, u32 base, u32 limit, u16 attribute);


/* 中斷處理函數 */
void    divide_error();
void    single_step_exception();
void    nmi();
void    breakpoint_exception();
void    overflow();
void    bounds_check();
void    inval_opcode();
void    copr_not_available();
void    double_fault();
void    copr_seg_overrun();
void    inval_tss();
void    segment_not_present();
void    stack_exception();
void    general_protection();
void    page_fault();
void    copr_error();
void    hwint00();
void    hwint01();
void    hwint02();
void    hwint03();
void    hwint04();
void    hwint05();
void    hwint06();
void    hwint07();
void    hwint08();
void    hwint09();
void    hwint10();
void    hwint11();
void    hwint12();
void    hwint13();
void    hwint14();
void    hwint15();


/*======================================================================*
                            init_prot
 *----------------------------------------------------------------------*
 初始化 IDT
 *======================================================================*/
PUBLIC void init_prot()
{
    init_8259A();

    // 全部初始化成中斷門(沒有陷阱門)
    init_idt_desc(INT_VECTOR_DIVIDE,      DA_386IGate, divide_error,          PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_DEBUG,       DA_386IGate, single_step_exception, PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_NMI,         DA_386IGate, nmi,                   PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_BREAKPOINT,  DA_386IGate, breakpoint_exception,  PRIVILEGE_USER);
    init_idt_desc(INT_VECTOR_OVERFLOW,    DA_386IGate, overflow,              PRIVILEGE_USER);
    init_idt_desc(INT_VECTOR_BOUNDS,      DA_386IGate, bounds_check,          PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_INVAL_OP,    DA_386IGate, inval_opcode,          PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_COPROC_NOT,  DA_386IGate, copr_not_available,    PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_DOUBLE_FAULT,DA_386IGate, double_fault,          PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_COPROC_SEG,  DA_386IGate, copr_seg_overrun,      PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_INVAL_TSS,   DA_386IGate, inval_tss,             PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_SEG_NOT,     DA_386IGate, segment_not_present,   PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_STACK_FAULT, DA_386IGate, stack_exception,       PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_PROTECTION,  DA_386IGate, general_protection,    PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_PAGE_FAULT,  DA_386IGate, page_fault,            PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_COPROC_ERR,  DA_386IGate, copr_error,            PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ0 + 0,    DA_386IGate, hwint00,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ0 + 1,    DA_386IGate, hwint01,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ0 + 2,    DA_386IGate, hwint02,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ0 + 3,    DA_386IGate, hwint03,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ0 + 4,    DA_386IGate, hwint04,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ0 + 5,    DA_386IGate, hwint05,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ0 + 6,    DA_386IGate, hwint06,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ0 + 7,    DA_386IGate, hwint07,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ8 + 0,    DA_386IGate, hwint08,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ8 + 1,    DA_386IGate, hwint09,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ8 + 2,    DA_386IGate, hwint10,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ8 + 3,    DA_386IGate, hwint11,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ8 + 4,    DA_386IGate, hwint12,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ8 + 5,    DA_386IGate, hwint13,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ8 + 6,    DA_386IGate, hwint14,               PRIVILEGE_KRNL);
    init_idt_desc(INT_VECTOR_IRQ8 + 7,    DA_386IGate, hwint15,               PRIVILEGE_KRNL);

    /* 填充 GDT 中 TSS 這個描述符 */
    memset(&tss, 0, sizeof(tss));
    tss.ss0 = SELECTOR_KERNEL_DS;
    init_descriptor(&gdt[INDEX_TSS],
            vir2phys(seg2phys(SELECTOR_KERNEL_DS), &tss),
            sizeof(tss) - 1,
            DA_386TSS);
    tss.iobase = sizeof(tss); /* 沒有I/O許可位圖 */

    /* 填充 GDT 中進程的 LDT 的描述符 */
    init_descriptor(&gdt[INDEX_LDT_FIRST],
        vir2phys(seg2phys(SELECTOR_KERNEL_DS), proc_table[0].ldts),
        LDT_SIZE * sizeof(DESCRIPTOR) - 1,
        DA_LDT);
}


/*======================================================================*
                             init_idt_desc
 *----------------------------------------------------------------------*
 初始化 386 中斷門
 *======================================================================*/
PUBLIC void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege)
{
    GATE *    p_gate    = &idt[vector];
    u32    base    = (u32)handler;
    p_gate->offset_low  = base & 0xFFFF;
    p_gate->selector    = SELECTOR_KERNEL_CS;
    p_gate->dcount      = 0;
    p_gate->attr        = desc_type | (privilege << 5);
    p_gate->offset_high = (base >> 16) & 0xFFFF;
}


/*======================================================================*
                           seg2phys
 *----------------------------------------------------------------------*
 由段名求絕對地址
 *======================================================================*/
PUBLIC u32 seg2phys(u16 seg)
{
    DESCRIPTOR* p_dest = &gdt[seg >> 3];
    return (p_dest->base_high<<24 | p_dest->base_mid<<16 | p_dest->base_low);
}

/*======================================================================*
                           init_descriptor
 *----------------------------------------------------------------------*
 初始化段描述符
 *======================================================================*/
PRIVATE void init_descriptor(DESCRIPTOR *p_desc,u32 base,u32 limit,u16 attribute)
{
    p_desc->limit_low    = limit & 0x0FFFF;
    p_desc->base_low    = base & 0x0FFFF;
    p_desc->base_mid    = (base >> 16) & 0x0FF;
    p_desc->attr1        = attribute & 0xFF;
    p_desc->limit_high_attr2= ((limit>>16) & 0x0F) | (attribute>>8) & 0xF0;
    p_desc->base_high    = (base >> 24) & 0x0FF;
}

/*======================================================================*
                            exception_handler
 *----------------------------------------------------------------------*
 異常處理
 *======================================================================*/
PUBLIC void exception_handler(int vec_no, int err_code, int eip, int cs, int eflags)
{
    int i;
    int text_color = 0x74; /* 灰底紅字 */
    char err_description[][64] = {    "#DE Divide Error",
                    "#DB RESERVED",
                    "—  NMI Interrupt",
                    "#BP Breakpoint",
                    "#OF Overflow",
                    "#BR BOUND Range Exceeded",
                    "#UD Invalid Opcode (Undefined Opcode)",
                    "#NM Device Not Available (No Math Coprocessor)",
                    "#DF Double Fault",
                    "    Coprocessor Segment Overrun (reserved)",
                    "#TS Invalid TSS",
                    "#NP Segment Not Present",
                    "#SS Stack-Segment Fault",
                    "#GP General Protection",
                    "#PF Page Fault",
                    "—  (Intel reserved. Do not use.)",
                    "#MF x87 FPU Floating-Point Error (Math Fault)",
                    "#AC Alignment Check",
                    "#MC Machine Check",
                    "#XF SIMD Floating-Point Exception"
                };

    /* 通過打印空格的方式清空屏幕的前五行,並把 disp_pos 清零 */
    disp_pos = 0;
    for(i=0;i<80*5;i++){
        disp_str(" ");
    }
    disp_pos = 0;

    disp_color_str("Exception! --> ", text_color);
    disp_color_str(err_description[vec_no], text_color);
    disp_color_str("\n\n", text_color);
    disp_color_str("EFLAGS:", text_color);
    disp_int(eflags);
    disp_color_str("CS:", text_color);
    disp_int(cs);
    disp_color_str("EIP:", text_color);
    disp_int(eip);

    if(err_code != 0xFFFFFFFF){
        disp_color_str("Error code:", text_color);
        disp_int(err_code);
    }
}

kernel/start.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            start.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "proto.h"
#include "string.h"
#include "proc.h"
#include "global.h"


/*======================================================================*
                            cstart
 *======================================================================*/
PUBLIC void cstart()
{
    disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n-----\"cstart\" begins-----\n");

    // 將 LOADER 中的 GDT 複製到新的 GDT 中
    memcpy(    &gdt,                    // New GDT
        (void*)(*((u32*)(&gdt_ptr[2]))),   // Base  of Old GDT
        *((u16*)(&gdt_ptr[0])) + 1        // Limit of Old GDT
        );
    // gdt_ptr[6] 共 6 個字節:0~15:Limit  16~47:Base。用作 sgdt 以及 lgdt 的參數。
    u16* p_gdt_limit = (u16*)(&gdt_ptr[0]);
    u32* p_gdt_base  = (u32*)(&gdt_ptr[2]);
    *p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1;
    *p_gdt_base  = (u32)&gdt;

    // idt_ptr[6] 共 6 個字節:0~15:Limit  16~47:Base。用作 sidt 以及 lidt 的參數。
    u16* p_idt_limit = (u16*)(&idt_ptr[0]);
    u32* p_idt_base  = (u32*)(&idt_ptr[2]);
    *p_idt_limit = IDT_SIZE * sizeof(GATE) - 1;
    *p_idt_base  = (u32)&idt;

    init_prot();

    disp_str("-----\"cstart\" finished-----\n");
}

lib/kliba.asm

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                              klib.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                                                       Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


; 導入全局變量
extern    disp_pos


[SECTION .text]

; 導出函數
global    disp_str
global    disp_color_str
global    out_byte
global    in_byte

; ========================================================================
;                  void disp_str(char * info);
; ========================================================================
disp_str:
    push   ebp
    mov    ebp, esp

    mov    esi, [ebp + 8]    ; pszInfo
    mov    edi, [disp_pos]
    mov    ah, 0Fh
.1:
    lodsb
    test   al, al
    jz     .2
    cmp    al, 0Ah    ; 是ENTER嗎?
    jnz    .3
    push   eax
    mov    eax, edi
    mov    bl, 160
    div    bl
    and    eax, 0FFh
    inc    eax
    mov    bl, 160
    mul    bl
    mov    edi, eax
    pop    eax
    jmp    .1
.3:
    mov    [gs:edi], ax
    add    edi, 2
    jmp    .1

.2:
    mov    [disp_pos], edi

    pop    ebp
    ret

; ========================================================================
;                  void disp_color_str(char * info, int color);
; ========================================================================
disp_color_str:
    push   ebp
    mov    ebp, esp

    mov    esi, [ebp + 8]    ; pszInfo
    mov    edi, [disp_pos]
    mov    ah, [ebp + 12]    ; color
.1:
    lodsb
    test   al, al
    jz     .2
    cmp    al, 0Ah    ; 是ENTER嗎?
    jnz    .3
    push   eax
    mov    eax, edi
    mov    bl, 160
    div    bl
    and    eax, 0FFh
    inc    eax
    mov    bl, 160
    mul    bl
    mov    edi, eax
    pop    eax
    jmp    .1
.3:
    mov    [gs:edi], ax
    add    edi, 2
    jmp    .1

.2:
    mov    [disp_pos], edi

    pop    ebp
    ret

; ========================================================================
;                  void out_byte(u16 port, u8 value);
; ========================================================================
out_byte:
    mov    edx, [esp + 4]        ; port
    mov    al, [esp + 4 + 4]    ; value
    out    dx, al
    nop    ; 一點延遲
    nop
    ret

; ========================================================================
;                  u8 in_byte(u16 port);
; ========================================================================
in_byte:
    mov    edx, [esp + 4]        ; port
    xor    eax, eax
    in     al, dx
    nop    ; 一點延遲
    nop
    ret

lib/klib.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            klib.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "proto.h"
#include "string.h"
#include "proc.h"
#include "global.h"


/*======================================================================*
                               itoa
 *======================================================================*/
PUBLIC char * itoa(char * str, int num)/* 數字前面的 0 不被顯示出來, 比如 0000B800 被顯示成 B800 */
{
    char * p = str;
    char   ch;
    int    i;
    int    flag = FALSE;

    *p++ = '0';
    *p++ = 'x';

    if(num == 0){
        *p++ = '0';
    }
    else{
        for(i=28;i>=0;i-=4){
            ch = (num >> i) & 0xF;
            if(flag || (ch > 0)){
                flag = TRUE;
                ch += '0';
                if(ch > '9'){
                    ch += 7;
                }
                *p++ = ch;
            }
        }
    }

    *p = 0;

    return str;
}


/*======================================================================*
                               disp_int
 *======================================================================*/
PUBLIC void disp_int(int input)
{
    char output[16];
    itoa(output, input);
    disp_str(output);
}

/*======================================================================*
                               delay
 *======================================================================*/
PUBLIC void delay(int time)
{
    int i, j, k;
    for (k = 0; k < time; k++) {
        for (i = 0; i < 10; i++) {
            for (j = 0; j < 10000; j++) {}
        }
    }
}

lib/string.asm

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                              string.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                                                       Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

[SECTION .text]

; 導出函數
global    memcpy
global    memset


; ------------------------------------------------------------------------
; void* memcpy(void* es:p_dst, void* ds:p_src, int size);
; ------------------------------------------------------------------------
memcpy:
    push   ebp
    mov    ebp, esp

    push   esi
    push   edi
    push   ecx

    mov    edi, [ebp + 8]     ; Destination
    mov    esi, [ebp + 12]    ; Source
    mov    ecx, [ebp + 16]    ; Counter
.1:
    cmp    ecx, 0             ; 判斷計數器
    jz    .2                  ; 計數器為零時跳出

    mov    al, [ds:esi]       ; ┓
    inc    esi                ; ┃
                              ; ┣ 逐字元移動
    mov    byte [es:edi], al  ; ┃
    inc    edi                ; ┛

    dec    ecx                ; 計數器減一
    jmp    .1                 ; 循環
.2:
    mov    eax, [ebp + 8]     ; 返回值

    pop    ecx
    pop    edi
    pop    esi
    mov    esp, ebp
    pop    ebp

    ret            ; 函數結束,返回
; memcpy 結束-------------------------------------------------------------


; ------------------------------------------------------------------------
; void memset(void* p_dst, char ch, int size);
; ------------------------------------------------------------------------
memset:
    push   ebp
    mov    ebp, esp

    push   esi
    push   edi
    push   ecx

    mov    edi, [ebp + 8]     ; Destination
    mov    edx, [ebp + 12]    ; Char to be putted
    mov    ecx, [ebp + 16]    ; Counter
.1:
    cmp    ecx, 0             ; 判斷計數器
    jz    .2                  ; 計數器為零時跳出

    mov    byte [edi], dl     ; ┓
    inc    edi                ; ┛

    dec    ecx                ; 計數器減一
    jmp    .1                 ; 循環
.2:

    pop    ecx
    pop    edi
    pop    esi
    mov    esp, ebp
    pop    ebp

    ret                       ; 函數結束,返回
; ------------------------------------------------------------------------


Makefile

#########################
# Makefile for Orange'S #
#########################

# Entry point of Orange'S
# It must have the same value with 'KernelEntryPointPhyAddr' in load.inc!
ENTRYPOINT = 0x30400

# Offset of entry point in kernel file
# It depends on ENTRYPOINT
ENTRYOFFSET =   0x400

# Programs, flags, etc.
ASM  = nasm
DASM  = ndisasm
CC  = gcc
LD  = ld
ASMBFLAGS = -I boot/include/
ASMKFLAGS = -I include/ -f elf
CFLAGS      = -I include/ -m32 -c -fno-builtin -fno-stack-protector
LDFLAGS     = -s  -melf_i386 -Ttext $(ENTRYPOINT)
DASMFLAGS = -u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)

# This Program
ORANGESBOOT = boot/boot.bin boot/loader.bin
ORANGESKERNEL = kernel.bin
OBJS  = kernel/kernel.o kernel/start.o kernel/main.o\
   kernel/i8259.o kernel/global.o kernel/protect.o\
   lib/kliba.o lib/klib.o lib/string.o
DASMOUTPUT = kernel.bin.asm

# All Phony Targets
.PHONY : everything final image clean realclean disasm all buildimg

# Default starting position
everything : $(ORANGESBOOT) $(ORANGESKERNEL)

all : realclean everything

final : all clean

image : final buildimg

clean :
 rm -f $(OBJS)

realclean :
 rm -f $(OBJS) $(ORANGESBOOT) $(ORANGESKERNEL)

disasm :
 $(DASM) $(DASMFLAGS) $(ORANGESKERNEL) > $(DASMOUTPUT)

# We assume that "a.img" exists in current folder
buildimg :
 mkdir tmp
 sleep 1
 dd if=boot/boot.bin of=a.img bs=512 count=1 conv=notrunc
 sleep 1
 sudo mount -o loop a.img tmp
 sleep 1
 sudo cp -fv boot/loader.bin tmp
 sudo cp -fv kernel.bin tmp
 sleep 1
 sudo umount tmp
 sleep 1
 rmdir tmp

boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
 $(ASM) $(ASMBFLAGS) -o $@ $<

boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc boot/include/pm.inc
 $(ASM) $(ASMBFLAGS) -o $@ $<

$(ORANGESKERNEL) : $(OBJS)
 $(LD) $(LDFLAGS) -o $(ORANGESKERNEL) $(OBJS)

kernel/kernel.o : kernel/kernel.asm include/sconst.inc
 $(ASM) $(ASMKFLAGS) -o $@ $<

kernel/start.o: kernel/start.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
   include/global.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/main.o: kernel/main.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
   include/global.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/i8259.o: kernel/i8259.c include/type.h include/const.h include/protect.h include/proto.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/global.o: kernel/global.c include/type.h include/const.h include/protect.h include/proc.h \
   include/global.h include/proto.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/protect.o: kernel/protect.c include/type.h include/const.h include/protect.h include/proc.h include/proto.h \
   include/global.h
 $(CC) $(CFLAGS) -o $@ $<

lib/klib.o: lib/klib.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
   include/global.h
 $(CC) $(CFLAGS) -o $@ $<

lib/kliba.o : lib/kliba.asm
 $(ASM) $(ASMKFLAGS) -o $@ $<

lib/string.o : lib/string.asm
 $(ASM) $(ASMKFLAGS) -o $@ $<
執行結果

回顧

第一個處理序的啟動過程示意圖

留言

這個網誌中的熱門文章

用 C# 批次控制 Word 合併列印

前由 我有全區的電話資料,問題在於我要依不同里別來製作出電話簿。結果如下圖: 單純採用合併列印無法達成我的需求。解決方法係用「功能變數」儲存上一個里別,與現在里別進行比較:若不同,則換頁。不過,這樣功能變數還蠻長的。最後,我還是採用 C# 來解決。 解決方案 用 C# 控制 WORD 中合併列印的「資料來源 Data Source」,給予不同里別的「sqlstatement」。迴圈處理不同的里別即可。但可預見其處理過程會很慢,不過還好,我可以不用在意它,有跑出結果即可。 程式碼 IList<string> areas = new List<string>() { "後壁", "侯伯", "嘉苳", "土溝", "嘉田", "嘉民", "菁豊", "崁頂", "後廍", "墨林", "菁寮", "新嘉", "頂長", "平安", "仕安", "竹新", "新東", "長安", "頂安", "福安", "烏樹" }; string root = @"D:\"; // 根目錄 string data = root + @"\data.docm"; // 資料檔(即資料來源) string template = root + @"\template.docx"; // 已設定好格式與合併欄位的 Word 檔 string output = @"d:\Final"; // 輸出之資料夾 object oMissing = System.Reflection.Missing.Va...

VLC c# 順利編譯

原文網址: http://www.cnblogs.com/haibindev/archive/2011/12/21/2296173.html 原文作者: haibindev 原文標題:c#万能视频播放器 本文的重點在於修正 class VlcPlayer,使其能順利在 VC# Express 2010 .Net Framework 4 下順利編譯。 修正重點在於 CallingConvention = CallingConvention. StdCall 改成 CallingConvention = CallingConvention. Cdecl using System; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace VlcDotNet { class VlcPlayer { private IntPtr libvlc_instance_; private IntPtr libvlc_media_player_; private double duration_; public VlcPlayer(string pluginPath) { string plugin_arg = "--plugin-path=" + pluginPath; string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", plugin_arg }; libvlc_instance_ = LibVlcAPI.libvlc_new(arguments); libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_); } public ...

[Symfony+Doctrine] 透過非 Id 來使用 Pessimistic Lock

根據 文件 ,Doctrine 有 Pessimistic Lock,又分為兩種: LockMode::PESSIMISTIC_WRITE:對應至 MySQL 的 Select FOR UPDATE LockMode::PESSIMISTIC_READ:對應至 MySQL 的 Select LOCK IN SHARE MODE 差別在於 LOCK IN SHARE MODE 會將在 row 的資料鎖定(row-level lock),在非同一交易(Transaction)下,不給寫入,其他交易可以讀取, 且可以繼續 Select LOCK IN SHARE MODE 。而 FOR UPDATE 不僅鎖定該資料,在非同一交易下,不給寫入,其它交易可以讀取, 但不能 Select LOCK IN SHARE MODE 。MySQL 文件有更詳細的比較與情境使用的說明,參考 網址 。 現在問題是,我們要完全採用 ORM 來處理資料。Doctrine 的文件提到 EntityManager::find 可以採用 Pessimistic Lock, 但 find 是透過 id 來處理 。而其他 find 系列函數(包括:findAll, findBy, findOneBy)皆不支援 LockMode。 因此,勢必要有方法來「透過非 id 來使用 Pessimistic Lock」。透過查看原始碼,簡單的方法是有的,解法之範例如下: 19 public function depositAction() 20 { 21 22 $em = $this->getDoctrine()->getManager(); 23 24 $em->transactional(function ($em) { 25 $entityName = 'AcmeTrainingBundle:Account'; 26 $lockMode = LockMode::PESSIMISTIC_READ; 27 $orderBy = null; 28 $...