跳到主要內容

遲到的處理序-里程碑式的成果

Orange'S 的運轉過程

程式碼

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>  */

/* Hardware interrupts */
#define NR_IRQ  16 /* Number of IRQs */
#define CLOCK_IRQ 0
#define KEYBOARD_IRQ 1
#define CASCADE_IRQ 2 /* cascade enable for 2nd AT controller */
#define ETHER_IRQ 3 /* default ethernet interrupt vector */
#define SECONDARY_IRQ 3 /* RS232 interrupt vector for port 2 */
#define RS232_IRQ 4 /* RS232 interrupt vector for port 1 */
#define XT_WINI_IRQ 5 /* xt winchester */
#define FLOPPY_IRQ 6 /* floppy disk */
#define PRINTER_IRQ 7
#define AT_WINI_IRQ 14 /* at winchester */


#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 u32  k_reenter;

EXTERN TSS  tss;
EXTERN PROCESS* p_proc_ready;

extern PROCESS  proc_table[];
extern char  task_stack[];
extern  TASK            task_table[];
extern irq_handler irq_table[];

include/proc.h

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


typedef struct s_stackframe { /* proc_ptr points here    ↑ Low   */
 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 address for assembly code save() │   */
 u32 eip;  /*  ┓      │   */
 u32 cs;  /*  ┃      │   */
 u32 eflags;  /*  ┣ these are pushed by CPU during interrupt │   */
 u32 esp;  /*  ┃      │   */
 u32 ss;  /*  ┛      ┷High   */
}STACK_FRAME;


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

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


typedef struct s_task {
 task_f initial_eip;
 int stacksize;
 char name[32];
}TASK;


/* Number of tasks */
#define NR_TASKS 3

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

#define STACK_SIZE_TOTAL (STACK_SIZE_TESTA + \
    STACK_SIZE_TESTB + \
    STACK_SIZE_TESTC)

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();
void TestB();
void TestC();

/* i8259.c */
PUBLIC void put_irq_handler(int irq, irq_handler handler);
PUBLIC void spurious_irq(int irq);

/* clock.c */
PUBLIC void clock_handler(int irq);

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

INT_M_CTL equ 0x20 ; I/O port for interrupt controller         <Master>
INT_M_CTLMASK equ 0x21 ; setting bits in this port disables ints   <Master>
INT_S_CTL equ 0xA0 ; I/O port for second interrupt controller  <Slave>
INT_S_CTLMASK equ 0xA1 ; setting bits in this port disables ints   <Slave>

EOI  equ 0x20

; 以下選擇子值必須與 protect.h 中保持一致!!!
SELECTOR_FLAT_C  equ  0x08  ; LOADER 裡面已經確定了的.
SELECTOR_TSS  equ  0x20  ; TSS. 從外層跳到內存時 SS 和 ESP 的值從裡面獲得.
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) ();
typedef void (*task_f) ();
typedef void (*irq_handler) (int irq);


#endif /* _ORANGES_TYPE_H_ */

kernel/clock.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                               clock.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"


/*======================================================================*
                           clock_handler
 *======================================================================*/
PUBLIC void clock_handler(int irq)
{
 disp_str("#");

 if (k_reenter != 0) {
  disp_str("!");
  return;
 }

 p_proc_ready++;
 if (p_proc_ready >= proc_table + NR_TASKS) {
  p_proc_ready = proc_table;
 }
}

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];

PUBLIC TASK task_table[NR_TASKS] = {{TestA, STACK_SIZE_TESTA, "TestA"},
     {TestB, STACK_SIZE_TESTB, "TestB"},
     {TestC, STACK_SIZE_TESTC, "TestC"}};

PUBLIC irq_handler  irq_table[NR_IRQ];

kernel/i8259.c

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


#include "type.h"
#include "const.h"
#include "protect.h"
#include "proto.h"
#include "proc.h"
#include "global.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.

 int i;
 for (i = 0; i < NR_IRQ; i++)
  irq_table[i] = spurious_irq;
}

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

/*======================================================================*
                           put_irq_handler
 *======================================================================*/
PUBLIC void put_irq_handler(int irq, irq_handler handler)
{
 disable_irq(irq);
 irq_table[irq] = handler;
}

kernel/kernel.asm

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


%include "sconst.inc"

; 導入函數
extern cstart
extern kernel_main
extern exception_handler
extern spurious_irq
extern clock_handler
extern disp_str
extern delay
extern irq_table

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

bits 32

[SECTION .data]
clock_int_msg  db "^", 0

[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
 call save
 in al, INT_M_CTLMASK ; `.
 or al, (1 << %1)  ;  | 屏蔽當前中斷
 out INT_M_CTLMASK, al ; /
 mov al, EOI   ; `. 置EOI位
 out INT_M_CTL, al  ; /
 sti ; CPU在響應中斷的過程中會自動關中斷,這句之後就允許響應新的中斷
 push %1   ; `.
 call [irq_table + 4 * %1] ;  | 中斷處理程序
 pop ecx   ; /
 cli
 in al, INT_M_CTLMASK ; `.
 and al, ~(1 << %1)  ;  | 恢復接受當前中斷
 out INT_M_CTLMASK, al ; /
 ret
%endmacro


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

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

; ====================================================================================
;                                   save
; ====================================================================================
save:
        pushad          ; `.
        push    ds      ;  |
        push    es      ;  | 保存原暫存器值
        push    fs      ;  |
        push    gs      ; /
        mov     dx, ss
        mov     ds, dx
        mov     es, dx

        mov     eax, esp                    ;eax = 進程表起始位址

        inc     dword [k_reenter]           ;k_reenter++;
        cmp     dword [k_reenter], 0        ;if(k_reenter ==0)
        jne     .1                          ;{
        mov     esp, StackTop               ;  mov esp, StackTop <--切換到內核堆疊
        push    restart                     ;  push restart
        jmp     [eax + RETADR - P_STACKBASE];  return;
.1:                                         ;} else { 已經在內核堆疊,不需要再切換
        push    restart_reenter             ;  push restart_reenter
        jmp     [eax + RETADR - P_STACKBASE];  return;
                                            ;}

; ====================================================================================
;                                   restart
; ====================================================================================
restart:
 mov esp, [p_proc_ready]
 lldt [esp + P_LDT_SEL]
 lea eax, [esp + P_STACKTOP]
 mov dword [tss + TSS3_S_SP0], eax
restart_reenter:
 dec dword [k_reenter]
 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");

 TASK*  p_task  = task_table;
 PROCESS* p_proc  = proc_table;
 char*  p_task_stack = task_stack + STACK_SIZE_TOTAL;
 u16  selector_ldt = SELECTOR_LDT_FIRST;
 int i;
 for (i = 0; i < NR_TASKS; i++) {
  strcpy(p_proc->p_name, p_task->name); // name of the process
  p_proc->pid = i;   // pid

  p_proc->ldt_sel = selector_ldt;

  memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],
         sizeof(DESCRIPTOR));
  p_proc->ldts[0].attr1 = DA_C | PRIVILEGE_TASK << 5;
  memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],
         sizeof(DESCRIPTOR));
  p_proc->ldts[1].attr1 = DA_DRW | PRIVILEGE_TASK << 5;
  p_proc->regs.cs = ((8 * 0) & SA_RPL_MASK & SA_TI_MASK)
   | SA_TIL | RPL_TASK;
  p_proc->regs.ds = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)
   | SA_TIL | RPL_TASK;
  p_proc->regs.es = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)
   | SA_TIL | RPL_TASK;
  p_proc->regs.fs = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)
   | SA_TIL | RPL_TASK;
  p_proc->regs.ss = ((8 * 1) & 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)p_task->initial_eip;
  p_proc->regs.esp = (u32)p_task_stack;
  p_proc->regs.eflags = 0x1202; /* IF=1, IOPL=1 */

  p_task_stack -= p_task->stacksize;
  p_proc++;
  p_task++;
  selector_ldt += 1 << 3;
 }

 k_reenter = 0;

 p_proc_ready = proc_table;

        put_irq_handler(CLOCK_IRQ, clock_handler); /* 設定時鐘中斷處理程序 */
        enable_irq(CLOCK_IRQ);                     /* 讓8259A可以接收時鐘中斷 */

 restart();

 while(1){}
}

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

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

/*======================================================================*
                               TestB
 *======================================================================*/
void TestC()
{
 int i = 0x2000;
 while(1){
  disp_str("C");
  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 的描述符
 int i;
 PROCESS* p_proc = proc_table;
 u16 selector_ldt = INDEX_LDT_FIRST << 3;
 for(i=0;i<NR_TASKS;i++){
  init_descriptor(&gdt[selector_ldt>>3],
    vir2phys(seg2phys(SELECTOR_KERNEL_DS),
     proc_table[i].ldts),
    LDT_SIZE * sizeof(DESCRIPTOR) - 1,
    DA_LDT);
  p_proc++;
  selector_ldt += 1 << 3;
 }
}


/*======================================================================*
                             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;  // 段界限 1  (2 字節)
 p_desc->base_low  = base & 0x0FFFF;  // 段基址 1  (2 字節)
 p_desc->base_mid  = (base >> 16) & 0x0FF;  // 段基址 2  (1 字節)
 p_desc->attr1   = attribute & 0xFF;  // 屬性 1
 p_desc->limit_high_attr2 = ((limit >> 16) & 0x0F) |
      (attribute >> 8) & 0xF0;// 段界限 2 + 屬性 2
 p_desc->base_high  = (base >> 24) & 0x0FF;  // 段基址 3  (1 字節)
}

/*======================================================================*
                            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
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

%include "sconst.inc"

; 導入全局變量
extern disp_pos


[SECTION .text]

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


; ========================================================================
;                  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

; ========================================================================
;                  void disable_irq(int irq);
; ========================================================================
; Disable an interrupt request line by setting an 8259 bit.
; Equivalent code:
; if(irq < 8)
;  out_byte(INT_M_CTLMASK, in_byte(INT_M_CTLMASK) | (1 << irq));
; else
;  out_byte(INT_S_CTLMASK, in_byte(INT_S_CTLMASK) | (1 << irq));
disable_irq:
        mov     ecx, [esp + 4]          ; irq
        pushf
        cli
        mov     ah, 1
        rol     ah, cl                  ; ah = (1 << (irq % 8))
        cmp     cl, 8
        jae     disable_8               ; disable irq >= 8 at the slave 8259
disable_0:
        in      al, INT_M_CTLMASK
        test    al, ah
        jnz     dis_already             ; already disabled?
        or      al, ah
        out     INT_M_CTLMASK, al       ; set bit at master 8259
        popf
        mov     eax, 1                  ; disabled by this function
        ret
disable_8:
        in      al, INT_S_CTLMASK
        test    al, ah
        jnz     dis_already             ; already disabled?
        or      al, ah
        out     INT_S_CTLMASK, al       ; set bit at slave 8259
        popf
        mov     eax, 1                  ; disabled by this function
        ret
dis_already:
        popf
        xor     eax, eax                ; already disabled
        ret

; ========================================================================
;                  void enable_irq(int irq);
; ========================================================================
; Enable an interrupt request line by clearing an 8259 bit.
; Equivalent code:
;       if(irq < 8)
;               out_byte(INT_M_CTLMASK, in_byte(INT_M_CTLMASK) & ~(1 << irq));
;       else
;               out_byte(INT_S_CTLMASK, in_byte(INT_S_CTLMASK) & ~(1 << irq));
;
enable_irq:
        mov     ecx, [esp + 4]          ; irq
        pushf
        cli
        mov     ah, ~1
        rol     ah, cl                  ; ah = ~(1 << (irq % 8))
        cmp     cl, 8
        jae     enable_8                ; enable irq >= 8 at the slave 8259
enable_0:
        in      al, INT_M_CTLMASK
        and     al, ah
        out     INT_M_CTLMASK, al       ; clear bit at master 8259
        popf
        ret
enable_8:
        in      al, INT_S_CTLMASK
        and     al, ah
        out     INT_S_CTLMASK, al       ; clear bit at slave 8259
        popf
        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<10000;i++){ for Virtual PC */
  for(i=0;i<10;i++){/* for Bochs */
   for(j=0;j<10000;j++){}
  }
 }
}

lib/string.asm

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

[SECTION .text]

; 導出函數
global memcpy
global memset
global  strcpy


; ------------------------------------------------------------------------
; 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   ; 函數結束,返回
; ------------------------------------------------------------------------


; ------------------------------------------------------------------------
; char* strcpy(char* p_dst, char* p_src);
; ------------------------------------------------------------------------
strcpy:
 push    ebp
 mov     ebp, esp

 mov     esi, [ebp + 12] ; Source
 mov     edi, [ebp + 8]  ; Destination

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

 cmp     al, 0           ; 是否遇到 '\0'
 jnz     .1              ; 沒遇到就繼續循環,遇到就結束

 mov     eax, [ebp + 8]  ; 返回值

 pop     ebp
 ret                     ; 函數結束,返回
; strcpy 結束-------------------------------------------------------------

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/clock.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

image : realclean everything clean 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
 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/clock.o: kernel/clock.c
 $(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 $...