跳到主要內容

處理序間通訊(IPC, Inter-Process Communication)

採用微核心。

IPC 分為兩種:

  • 非同步 IPC:送完訊息就不管了
  • 同步 IPC:發送者一直等到接收者收到訊息才放手,接收者接不到訊息就一直等著。優勢如下:
    • 作業系統無須另外維護緩衝區來存放正在傳遞的訊息
    • 作業系統無須保留一份訊息副本
    • 作業系統無須維護接收佇列(發送佇列還是需要的)
    • 發送者和接收者都可在任何時刻清晰且容易第知道訊息是否送達。
假設有處理序 A 想要向 B 發送訊息 M,其過程如下:
  1. A 首先準備好 M
  2. A 透過系統使用 sendrec,最終使用 msg_send
  3. 簡單判斷是否發生鎖死
  4. 判斷目標處理序 B 是否正在等待來自 A 的訊息
    • 如果是:訊息被複製給 B,B被解除阻塞,繼續執行
    • 如果否:A 被阻塞,並被加入到 B 的發送佇列中

假設有處理序 B 想要接收訊息(來自特定處理序、中斷或者任意處理序),其過程如下:
  1. B 準備一個空的訊息結構體 M,用於接收訊息
  2. B 通過系統使用 sendrec,最終使用 msg_receive
  3. 判斷 B 是否有個來自硬體的訊息(通過 has_int_msg),如果是,且 B 準備接收來自中斷的訊息或準備接收任意訊息,則馬上準備一個訊息給 B,並返回。
  4. 如果 B 想接收來自任意處理序的訊息,則從自己的發送佇列中選取締一個(如果佇列非空的話),將其訊息複製給 M
  5. 如果 B 想接收來自特定處理序 A 的訊息,則先判斷 A 是否正在等待向 B 發送訊息,若是的話,將其訊息複製給 M
  6. 如果此時沒有任何處理序發訊息給 B,B 會被阻塞

程式碼

include/string.h (新增)

/**
 * `phys_copy' and `phys_set' are used only in the kernel, where segments
 * are all flat (based on 0). In the meanwhile, currently linear address
 * space is mapped to the identical physical address space. Therefore,
 * a `physical copy' will be as same as a common copy, so does `phys_set'.
 */
#define   phys_copy   memcpy
#define   phys_set    memset

include/console.h

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

#ifndef _ORANGES_CONSOLE_H_
#define _ORANGES_CONSOLE_H_


/* CONSOLE */
typedef struct s_console
{
 unsigned int current_start_addr; /* 當前顯示到了什麼位置   */
 unsigned int original_addr;  /* 當前控制台對應顯存位置 */
 unsigned int v_mem_limit;  /* 當前控制台占的顯存大小 */
 unsigned int cursor;   /* 當前光標位置 */
}CONSOLE;

#define SCR_UP 1 /* scroll forward */
#define SCR_DN -1 /* scroll backward */

#define SCREEN_SIZE  (80 * 25)
#define SCREEN_WIDTH  80

#define DEFAULT_CHAR_COLOR 0x07 /* 0000 0111 黑底白字 */


#endif /* _ORANGES_CONSOLE_H_ */

include/const.h

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

#ifndef _ORANGES_CONST_H_
#define _ORANGES_CONST_H_


#define ASSERT
#ifdef ASSERT
void assertion_failure(char *exp, char *file, char *base_file, int line);
#define assert(exp if (exp); \
 else assertion_failure(#exp, __FILE__, __BASE_FILE__, __LINE__)
#else
#define assert(exp)
#endif

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

/* Color */
/*
 * e.g. MAKE_COLOR(BLUE, RED)
 *      MAKE_COLOR(BLACK, RED) | BRIGHT
 *      MAKE_COLOR(BLACK, RED) | BRIGHT | FLASH
 */
#define BLACK   0x0     /* 0000 */
#define WHITE   0x7     /* 0111 */
#define RED     0x4     /* 0100 */
#define GREEN   0x2     /* 0010 */
#define BLUE    0x1     /* 0001 */
#define FLASH   0x80    /* 1000 0000 */
#define BRIGHT  0x08    /* 0000 1000 */
#define MAKE_COLOR(x,y) (x | y) /* MAKE_COLOR(Background,Foreground) */

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

/* TTY */
#define NR_CONSOLES 3 /* consoles */

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

/* 8253/8254 PIT (Programmable Interval Timer) */
#define TIMER0         0x40 /* I/O port for timer channel 0 */
#define TIMER_MODE     0x43 /* I/O port for timer mode control */
#define RATE_GENERATOR 0x34 /* 00-11-010-0 :
        * Counter0 - LSB then MSB - rate generator - binary
        */
#define TIMER_FREQ     1193182L/* clock frequency for timer in PC and AT */
#define HZ             100  /* clock freq (software settable on IBM-PC) */

/* AT keyboard */
/* 8042 ports */
#define KB_DATA  0x60 /* I/O port for keyboard data
     Read : Read Output Buffer
     Write: Write Input Buffer(8042 Data&8048 Command) */
#define KB_CMD  0x64 /* I/O port for keyboard command
     Read : Read Status Register
     Write: Write Input Buffer(8042 Command) */
#define LED_CODE 0xED
#define KB_ACK  0xFA

/* VGA */
#define CRTC_ADDR_REG 0x3D4 /* CRT Controller Registers - Addr Register */
#define CRTC_DATA_REG 0x3D5 /* CRT Controller Registers - Data Register */
#define START_ADDR_H 0xC /* reg index of video mem start addr (MSB) */
#define START_ADDR_L 0xD /* reg index of video mem start addr (LSB) */
#define CURSOR_H 0xE /* reg index of cursor position (MSB) */
#define CURSOR_L 0xF /* reg index of cursor position (LSB) */
#define V_MEM_BASE 0xB8000 /* base of color video memory */
#define V_MEM_SIZE 0x8000 /* 32K: B8000H -> BFFFFH */

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

/* system call */
#define NR_SYS_CALL     2

#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  ticks;

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 int  nr_current_console;

extern PROCESS  proc_table[];
extern char  task_stack[];
extern  TASK            task_table[];
extern  TASK            user_proc_table[];
extern irq_handler irq_table[];
extern TTY  tty_table[];
extern  CONSOLE         console_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;               /* gdt selector giving ldt base and limit */
 DESCRIPTOR ldts[LDT_SIZE]; /* local descriptors for code and data */

        int ticks;                 /* remained ticks */
        int priority;

 u32 pid;                   /* process id passed in from MM */
 char p_name[16];           /* name of the process */

 int nr_tty;
}PROCESS;

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


/* Number of tasks & procs */
#define NR_TASKS 1
#define NR_PROCS 3

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

#define STACK_SIZE_TOTAL (STACK_SIZE_TTY + \
    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許可位圖 */
 /*u8 iomap[2];*/
}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. 從外層跳到內存時 SS 和 ESP 的值從裡面獲得.
#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

/* 描述符類型值說明 */
#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 陷阱門類型值   */

/* 選擇子類型值說明 */
/* 其中, 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 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 INT_VECTOR_SYS_CALL             0x90

/* 宏 */
/* 線性地址 → 物理地址 */
#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);
PUBLIC void init_clock();

/* keyboard.c */
PUBLIC void init_keyboard();

/* tty.c */
PUBLIC void task_tty();
PUBLIC void in_process(TTY* p_tty, u32 key);

/* console.c */
PUBLIC void out_char(CONSOLE* p_con, char ch);
PUBLIC void scroll_screen(CONSOLE* p_con, int direction);

/* printf.c */
PUBLIC  int     printf(const char *fmt, ...);

/* vsprintf.c */
PUBLIC  int     vsprintf(char *buf, const char *fmt, va_list args);

/* 以下是系統調用相關 */

/* 系統調用 - 系統級 */
/* proc.c */
PUBLIC  int     sys_get_ticks();
PUBLIC  int     sys_write(char* buf, int len, PROCESS* p_proc);
/* syscall.asm */
PUBLIC  void    sys_call();             /* int_handler */

/* 系統調用 - 用戶級 */
PUBLIC  int     get_ticks();
PUBLIC  void    write(char* buf, int len);

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 char *   va_list;

typedef void (*int_handler) ();
typedef void (*task_f) ();
typedef void (*irq_handler) (int irq);

typedef void* system_call;


#endif /* _ORANGES_TYPE_H_ */

kernel/console.c

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

/*
 迴車鍵: 把光標移到第一列
 換行鍵: 把光標前進到下一行
*/


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

PRIVATE void set_cursor(unsigned int position);
PRIVATE void set_video_start_addr(u32 addr);
PRIVATE void flush(CONSOLE* p_con);

/*======================================================================*
      init_screen
 *======================================================================*/
PUBLIC void init_screen(TTY* p_tty)
{
 int nr_tty = p_tty - tty_table;
 p_tty->p_console = console_table + nr_tty;

 int v_mem_size = V_MEM_SIZE >> 1; /* 顯存總大小 (in WORD) */

 int con_v_mem_size                   = v_mem_size / NR_CONSOLES;
 p_tty->p_console->original_addr      = nr_tty * con_v_mem_size;
 p_tty->p_console->v_mem_limit        = con_v_mem_size;
 p_tty->p_console->current_start_addr = p_tty->p_console->original_addr;

 /* 默認光標位置在最開始處 */
 p_tty->p_console->cursor = p_tty->p_console->original_addr;

 if (nr_tty == 0) {
  /* 第一個控制台沿用原來的光標位置 */
  p_tty->p_console->cursor = disp_pos / 2;
  disp_pos = 0;
 }
 else {
  out_char(p_tty->p_console, nr_tty + '0');
  out_char(p_tty->p_console, '#');
 }

 set_cursor(p_tty->p_console->cursor);
}


/*======================================================================*
      is_current_console
*======================================================================*/
PUBLIC int is_current_console(CONSOLE* p_con)
{
 return (p_con == &console_table[nr_current_console]);
}


/*======================================================================*
      out_char
 *======================================================================*/
PUBLIC void out_char(CONSOLE* p_con, char ch)
{
 u8* p_vmem = (u8*)(V_MEM_BASE + p_con->cursor * 2);

 switch(ch) {
 case '\n':
  if (p_con->cursor < p_con->original_addr +
      p_con->v_mem_limit - SCREEN_WIDTH) {
   p_con->cursor = p_con->original_addr + SCREEN_WIDTH *
    ((p_con->cursor - p_con->original_addr) /
     SCREEN_WIDTH + 1);
  }
  break;
 case '\b':
  if (p_con->cursor > p_con->original_addr) {
   p_con->cursor--;
   *(p_vmem-2) = ' ';
   *(p_vmem-1) = DEFAULT_CHAR_COLOR;
  }
  break;
 default:
  if (p_con->cursor <
      p_con->original_addr + p_con->v_mem_limit - 1) {
   *p_vmem++ = ch;
   *p_vmem++ = DEFAULT_CHAR_COLOR;
   p_con->cursor++;
  }
  break;
 }

 while (p_con->cursor >= p_con->current_start_addr + SCREEN_SIZE) {
  scroll_screen(p_con, SCR_DN);
 }

 flush(p_con);
}

/*======================================================================*
                           flush
*======================================================================*/
PRIVATE void flush(CONSOLE* p_con)
{
 if (is_current_console(p_con)) {
  set_cursor(p_con->cursor);
  set_video_start_addr(p_con->current_start_addr);
 }
}

/*======================================================================*
       set_cursor
 *======================================================================*/
PRIVATE void set_cursor(unsigned int position)
{
 disable_int();
 out_byte(CRTC_ADDR_REG, CURSOR_H);
 out_byte(CRTC_DATA_REG, (position >> 8) & 0xFF);
 out_byte(CRTC_ADDR_REG, CURSOR_L);
 out_byte(CRTC_DATA_REG, position & 0xFF);
 enable_int();
}

/*======================================================================*
     set_video_start_addr
 *======================================================================*/
PRIVATE void set_video_start_addr(u32 addr)
{
 disable_int();
 out_byte(CRTC_ADDR_REG, START_ADDR_H);
 out_byte(CRTC_DATA_REG, (addr >> 8) & 0xFF);
 out_byte(CRTC_ADDR_REG, START_ADDR_L);
 out_byte(CRTC_DATA_REG, addr & 0xFF);
 enable_int();
}



/*======================================================================*
      select_console
 *======================================================================*/
PUBLIC void select_console(int nr_console) /* 0 ~ (NR_CONSOLES - 1) */
{
 if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) {
  return;
 }

 nr_current_console = nr_console;

 flush(&console_table[nr_console]);
}

/*======================================================================*
      scroll_screen
 *----------------------------------------------------------------------*
 滾屏.
 *----------------------------------------------------------------------*
 direction:
 SCR_UP : 向上滾屏
 SCR_DN : 向下滾屏
 其它 : 不做處理
 *======================================================================*/
PUBLIC void scroll_screen(CONSOLE* p_con, int direction)
{
 if (direction == SCR_UP) {
  if (p_con->current_start_addr > p_con->original_addr) {
   p_con->current_start_addr -= SCREEN_WIDTH;
  }
 }
 else if (direction == SCR_DN) {
  if (p_con->current_start_addr + SCREEN_SIZE <
      p_con->original_addr + p_con->v_mem_limit) {
   p_con->current_start_addr += SCREEN_WIDTH;
  }
 }
 else{
 }

 flush(p_con);
}

kernel/global.c

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

#define GLOBAL_VARIABLES_HERE

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


PUBLIC PROCESS proc_table[NR_TASKS + NR_PROCS];

PUBLIC TASK task_table[NR_TASKS] = {
 {task_tty, STACK_SIZE_TTY, "tty"}};

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

PUBLIC char  task_stack[STACK_SIZE_TOTAL];

PUBLIC TTY  tty_table[NR_CONSOLES];
PUBLIC CONSOLE  console_table[NR_CONSOLES];

PUBLIC irq_handler irq_table[NR_IRQ];

PUBLIC system_call sys_call_table[NR_SYS_CALL] = {sys_get_ticks, sys_write};

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
extern sys_call_table

bits 32

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

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

[section .text] ; 程式碼在此

global _start ; 導出 _start

global restart
global sys_call

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 esp, StackTop',中間堅決不能用 push/pop 指令,
  ;; 因為當前 esp 指向 proc_table 裡的某個位置,push 會破壞掉處理序表,導致災難性後果!

  mov     esi, edx ; 保存 edx,因為 edx 裡保存了系統使用的參數
       ; (沒用堆疊,而是用了另一個暫存器 esi)
        mov     dx, ss
        mov     ds, dx
        mov     es, dx
  mov     fs, dx

  mov     edx, esi ; 恢復 esi

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

        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     [esi + RETADR - P_STACKBASE];  return;
.1:                                         ;} else { 已經在內核堆疊,不需要再切換
        push    restart_reenter             ;  push restart_reenter
        jmp     [esi + RETADR - P_STACKBASE];  return;
                                            ;}


; ====================================================================================
;                                 sys_call
; ====================================================================================
sys_call:
  call    save

  sti
  push sti

  push dword [p_proc_ready]
  push    edx
  push ecx
  push ebx
        call    [sys_call_table + eax * 4]
  add     esp, 4 * 4

  pop     esi
        mov     [esi + EAXREG - P_STACKBASE], eax
        cli

        ret


; ====================================================================================
;                                   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/keyboard.c

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

#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "keyboard.h"
#include "keymap.h"

PRIVATE KB_INPUT kb_in;

PRIVATE int code_with_E0;
PRIVATE int shift_l; /* l shift state */
PRIVATE int shift_r; /* r shift state */
PRIVATE int alt_l;  /* l alt state  */
PRIVATE int alt_r;  /* r left state  */
PRIVATE int ctrl_l;  /* l ctrl state  */
PRIVATE int ctrl_r;  /* l ctrl state  */
PRIVATE int caps_lock; /* Caps Lock  */
PRIVATE int num_lock; /* Num Lock  */
PRIVATE int scroll_lock; /* Scroll Lock  */
PRIVATE int column;

PRIVATE int caps_lock; /* Caps Lock  */
PRIVATE int num_lock; /* Num Lock  */
PRIVATE int scroll_lock; /* Scroll Lock  */

PRIVATE u8 get_byte_from_kbuf();
PRIVATE void    set_leds();
PRIVATE void    kb_wait();
PRIVATE void    kb_ack();

/*======================================================================*
                            keyboard_handler
 *======================================================================*/
PUBLIC void keyboard_handler(int irq)
{
 u8 scan_code = in_byte(KB_DATA);

 if (kb_in.count < KB_IN_BYTES) {
  *(kb_in.p_head) = scan_code;
  kb_in.p_head++;
  if (kb_in.p_head == kb_in.buf + KB_IN_BYTES) {
   kb_in.p_head = kb_in.buf;
  }
  kb_in.count++;
 }
}


/*======================================================================*
                           init_keyboard
*======================================================================*/
PUBLIC void init_keyboard()
{
 kb_in.count = 0;
 kb_in.p_head = kb_in.p_tail = kb_in.buf;

 shift_l = shift_r = 0;
 alt_l = alt_r   = 0;
 ctrl_l = ctrl_r  = 0;

 caps_lock   = 0;
 num_lock    = 1;
 scroll_lock = 0;

 set_leds();

        put_irq_handler(KEYBOARD_IRQ, keyboard_handler);/*設定鍵盤中斷處理程序*/
        enable_irq(KEYBOARD_IRQ);                       /*開鍵盤中斷*/
}


/*======================================================================*
                           keyboard_read
*======================================================================*/
PUBLIC void keyboard_read(TTY* p_tty)
{
 u8 scan_code;
 char output[2];
 int make; /* 1: make;  0: break. */

 u32 key = 0;/* 用一個整型來表示一個鍵。比如,如果 Home 被按下,
    * 則 key 值將為定義在 keyboard.h 中的 'HOME'。
    */
 u32* keyrow; /* 指向 keymap[] 的某一行 */

 if(kb_in.count > 0){
  code_with_E0 = 0;

  scan_code = get_byte_from_kbuf();

  /* 下面開始解析掃描碼 */
  if (scan_code == 0xE1) {
   int i;
   u8 pausebrk_scode[] = {0xE1, 0x1D, 0x45,
            0xE1, 0x9D, 0xC5};
   int is_pausebreak = 1;
   for(i=1;i<6;i++){
    if (get_byte_from_kbuf() != pausebrk_scode[i]) {
     is_pausebreak = 0;
     break;
    }
   }
   if (is_pausebreak) {
    key = PAUSEBREAK;
   }
  }
  else if (scan_code == 0xE0) {
   scan_code = get_byte_from_kbuf();

   /* PrintScreen 被按下 */
   if (scan_code == 0x2A) {
    if (get_byte_from_kbuf() == 0xE0) {
     if (get_byte_from_kbuf() == 0x37) {
      key = PRINTSCREEN;
      make = 1;
     }
    }
   }
   /* PrintScreen 被釋放 */
   if (scan_code == 0xB7) {
    if (get_byte_from_kbuf() == 0xE0) {
     if (get_byte_from_kbuf() == 0xAA) {
      key = PRINTSCREEN;
      make = 0;
     }
    }
   }
   /* 不是PrintScreen, 此時scan_code為0xE0緊跟的那個值. */
   if (key == 0) {
    code_with_E0 = 1;
   }
  }
  if ((key != PAUSEBREAK) && (key != PRINTSCREEN)) {
   /* 首先判斷Make Code 還是 Break Code */
   make = (scan_code & FLAG_BREAK ? 0 : 1);

   /* 先定位到 keymap 中的行 */
   keyrow = &keymap[(scan_code & 0x7F) * MAP_COLS];

   column = 0;

   int caps = shift_l || shift_r;
   if (caps_lock) {
    if ((keyrow[0] >= 'a') && (keyrow[0] <= 'z')){
     caps = !caps;
    }
   }
   if (caps) {
    column = 1;
   }

   if (code_with_E0) {
    column = 2;
   }

   key = keyrow[column];

   switch(key) {
   case SHIFT_L:
    shift_l = make;
    break;
   case SHIFT_R:
    shift_r = make;
    break;
   case CTRL_L:
    ctrl_l = make;
    break;
   case CTRL_R:
    ctrl_r = make;
    break;
   case ALT_L:
    alt_l = make;
    break;
   case ALT_R:
    alt_l = make;
    break;
   case CAPS_LOCK:
    if (make) {
     caps_lock   = !caps_lock;
     set_leds();
    }
    break;
   case NUM_LOCK:
    if (make) {
     num_lock    = !num_lock;
     set_leds();
    }
    break;
   case SCROLL_LOCK:
    if (make) {
     scroll_lock = !scroll_lock;
     set_leds();
    }
    break;
   default:
    break;
   }

   if (make) { /* 忽略 Break Code */
    int pad = 0;

    /* 首先處理小鍵盤 */
    if ((key >= PAD_SLASH) && (key <= PAD_9)) {
     pad = 1;
     switch(key) {
     case PAD_SLASH:
      key = '/';
      break;
     case PAD_STAR:
      key = '*';
      break;
     case PAD_MINUS:
      key = '-';
      break;
     case PAD_PLUS:
      key = '+';
      break;
     case PAD_ENTER:
      key = ENTER;
      break;
     default:
      if (num_lock &&
          (key >= PAD_0) &&
          (key <= PAD_9)) {
       key = key - PAD_0 + '0';
      }
      else if (num_lock &&
        (key == PAD_DOT)) {
       key = '.';
      }
      else{
       switch(key) {
       case PAD_HOME:
        key = HOME;
        break;
       case PAD_END:
        key = END;
        break;
       case PAD_PAGEUP:
        key = PAGEUP;
        break;
       case PAD_PAGEDOWN:
        key = PAGEDOWN;
        break;
       case PAD_INS:
        key = INSERT;
        break;
       case PAD_UP:
        key = UP;
        break;
       case PAD_DOWN:
        key = DOWN;
        break;
       case PAD_LEFT:
        key = LEFT;
        break;
       case PAD_RIGHT:
        key = RIGHT;
        break;
       case PAD_DOT:
        key = DELETE;
        break;
       default:
        break;
       }
      }
      break;
     }
    }

    key |= shift_l ? FLAG_SHIFT_L : 0;
    key |= shift_r ? FLAG_SHIFT_R : 0;
    key |= ctrl_l ? FLAG_CTRL_L : 0;
    key |= ctrl_r ? FLAG_CTRL_R : 0;
    key |= alt_l ? FLAG_ALT_L : 0;
    key |= alt_r ? FLAG_ALT_R : 0;
    key |= pad      ? FLAG_PAD      : 0;

    in_process(p_tty, key);
   }
  }
 }
}

/*======================================================================*
       get_byte_from_kbuf
 *======================================================================*/
PRIVATE u8 get_byte_from_kbuf()       /* 從鍵盤緩衝區中讀取下一個字節 */
{
        u8 scan_code;

        while (kb_in.count <= 0) {}   /* 等待下一個字節到來 */

        disable_int();
        scan_code = *(kb_in.p_tail);
        kb_in.p_tail++;
        if (kb_in.p_tail == kb_in.buf + KB_IN_BYTES) {
                kb_in.p_tail = kb_in.buf;
        }
        kb_in.count--;
        enable_int();

 return scan_code;
}

/*======================================================================*
     kb_wait
 *======================================================================*/
PRIVATE void kb_wait() /* 等待 8042 的輸入緩衝區空 */
{
 u8 kb_stat;

 do {
  kb_stat = in_byte(KB_CMD);
 } while (kb_stat & 0x02);
}


/*======================================================================*
     kb_ack
 *======================================================================*/
PRIVATE void kb_ack()
{
 u8 kb_read;

 do {
  kb_read = in_byte(KB_DATA);
 } while (kb_read =! KB_ACK);
}

/*======================================================================*
     set_leds
 *======================================================================*/
PRIVATE void set_leds()
{
 u8 leds = (caps_lock << 2) | (num_lock << 1) | scroll_lock;

 kb_wait();
 out_byte(KB_DATA, LED_CODE);
 kb_ack();

 kb_wait();
 out_byte(KB_DATA, leds);
 kb_ack();
}

kernel/main.c

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

#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.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;
        u8              privilege;
        u8              rpl;
        int             eflags;
 for (i = 0; i < NR_TASKS+NR_PROCS; i++) {
                if (i < NR_TASKS) {     /* 任務 */
                        p_task    = task_table + i;
                        privilege = PRIVILEGE_TASK;
                        rpl       = RPL_TASK;
                        eflags    = 0x1202; /* IF=1, IOPL=1, bit 2 is always 1 */
                }
                else {                  /* 用戶進程 */
                        p_task    = user_proc_table + (i - NR_TASKS);
                        privilege = PRIVILEGE_USER;
                        rpl       = RPL_USER;
                        eflags    = 0x202; /* IF=1, bit 2 is always 1 */
                }

  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 << 5;
  memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],
         sizeof(DESCRIPTOR));
  p_proc->ldts[1].attr1 = DA_DRW | privilege << 5;
  p_proc->regs.cs = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
  p_proc->regs.ds = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
  p_proc->regs.es = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
  p_proc->regs.fs = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
  p_proc->regs.ss = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
  p_proc->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;

  p_proc->regs.eip = (u32)p_task->initial_eip;
  p_proc->regs.esp = (u32)p_task_stack;
  p_proc->regs.eflags = eflags;

  p_proc->nr_tty = 0;

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

 proc_table[0].ticks = proc_table[0].priority = 15;
 proc_table[1].ticks = proc_table[1].priority =  5;
 proc_table[2].ticks = proc_table[2].priority =  5;
 proc_table[3].ticks = proc_table[3].priority =  5;

        proc_table[1].nr_tty = 0;
        proc_table[2].nr_tty = 1;
        proc_table[3].nr_tty = 1;

 k_reenter = 0;
 ticks = 0;

 p_proc_ready = proc_table;

 init_clock();
        init_keyboard();

 restart();

 while(1){}
}

/*======================================================================*
                               TestA
 *======================================================================*/
void TestA()
{
 int i = 0;
 while (1) {
  printf("<Ticks:%x>", get_ticks());
  milli_delay(200);
 }
}

/*======================================================================*
                               TestB
 *======================================================================*/
void TestB()
{
 int i = 0x1000;
 while(1){
  printf("B");
  milli_delay(200);
 }
}

/*======================================================================*
                               TestB
 *======================================================================*/
void TestC()
{
 int i = 0x2000;
 while(1){
  printf("C");
  milli_delay(200);
 }
}

kernel/printf.c

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

#include "type.h"
#include "const.h"

/******************************************************************************************
                        可變參數函數調用原理(其中涉及的數字皆為舉例)
===========================================================================================

i = 0x23;
j = 0x78;
char fmt[] = "%x%d";
printf(fmt, i, j);

        push    j
        push    i
        push    fmt
        call    printf
        add     esp, 3 * 4


                ┃        HIGH        ┃                        ┃        HIGH        ┃
                ┃        ...         ┃                        ┃        ...         ┃
                ┣━━━━━━━━━━┫                        ┣━━━━━━━━━━┫
                ┃                    ┃                 0x32010┃        '\0'        ┃
                ┣━━━━━━━━━━┫                        ┣━━━━━━━━━━┫
         0x3046C┃        0x78        ┃                 0x3200c┃         d          ┃
                ┣━━━━━━━━━━┫                        ┣━━━━━━━━━━┫
   arg = 0x30468┃        0x23        ┃                 0x32008┃         %          ┃
                ┣━━━━━━━━━━┫                        ┣━━━━━━━━━━┫
         0x30464┃      0x32000 ───╂────┐       0x32004┃         x          ┃
                ┣━━━━━━━━━━┫        │              ┣━━━━━━━━━━┫
                ┃                    ┃        └──→ 0x32000┃         %          ┃
                ┣━━━━━━━━━━┫                        ┣━━━━━━━━━━┫
                ┃        ...         ┃                        ┃        ...         ┃
                ┃        LOW         ┃                        ┃        LOW         ┃

實際上,調用 vsprintf 的情形是這樣的:

        vsprintf(buf, 0x32000, 0x30468);

******************************************************************************************/

/*======================================================================*
                                 printf
 *======================================================================*/
int printf(const char *fmt, ...)
{
 int i;
 char buf[256];

 va_list arg = (va_list)((char*)(&fmt) + 4); /*4是參數fmt所占堆棧中的大小*/
 i = vsprintf(buf, fmt, arg);
 write(buf, i);

 return i;
}

kernel/proc.c

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

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

/*======================================================================*
                              schedule
 *======================================================================*/
PUBLIC void schedule()
{
 PROCESS* p;
 int  greatest_ticks = 0;

 while (!greatest_ticks) {
  for (p = proc_table; p < proc_table+NR_TASKS+NR_PROCS; p++) {
   if (p->ticks > greatest_ticks) {
    greatest_ticks = p->ticks;
    p_proc_ready = p;
   }
  }

  if (!greatest_ticks) {
   for(p=proc_table;p<proc_table+NR_TASKS+NR_PROCS;p++) {
    p->ticks = p->priority;
   }
  }
 }
}

/*======================================================================*
                           sys_get_ticks
 *======================================================================*/
PUBLIC int sys_get_ticks()
{
 return ticks;
}




/***********************************************************************
 *                   sys_sendrec
 ***********************************************************************/
/**
 * <Ring 0> The core routine of system call `sendrec()'.
 *
 * @parm function SEND or RECEIVE
 * @parm src_dest To/From whom the message is transferred.
 * @parm m        Ptr to the MESSAGE body
 * @parm p        The caller proc.
 *
 * @return Zero if success.
 ***********************************************************************/
PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* m, struct proc*p)
{
 assert(k_reenter == 0); /* make sure we are not in ring0 */
    assert((src_dest >= 0 && src_dest < NR_TASKS + NR_PROCS) ||
  src_dest == ANY ||
  src_dest == INTERRUPT);

 int ret = 0;
 int caller = proc2pid(p);
 MESSAGE* mla = (MESSAGE*)va2la(caller, m);
 mla->source = caller;

    assert(mla->source != src_dest);

 /**
  * Actually we have the third message type: BOTH. However, it is not allowed to be passed to the kernel directly. 
     * Kernel doesn't know it at all. It is transformed into a SEND followed by a RECEIVE by `send_recv()'.
     */
 if (function == SEND) {
  ret = msg_send(p, src_dest, m);
  if (ret != 0)
   return ret;
 }
 else if (function == RECEIVE) {
  ret = msg_receive(p, src_dest, m);
  if (ret != 0)
   return ret;
 }
 else {
  panic("{sys_sendrec} invalid function: "
     "%d (SEND:%d, RECEIVE:%d).", function, SEND, RECEIVE);
 }

 return 0;
}

kernel/protect.c

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

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

 init_idt_desc(INT_VECTOR_SYS_CALL, DA_386IGate,
        sys_call,   PRIVILEGE_USER);

 /* 填充 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+NR_PROCS; 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 "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.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");
}

kernel/syscall.asm

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

%include "sconst.inc"

INT_VECTOR_SYS_CALL equ 0x90
_NR_get_ticks       equ 0
_NR_write     equ 1

; 導出符號
global get_ticks
global write
global  sednrec

bits 32
[section .text]

; ====================================================================
;                              get_ticks
; ====================================================================
get_ticks:
 mov eax, _NR_get_ticks
 int INT_VECTOR_SYS_CALL
 ret


; ====================================================================
;          sendrec(int function, int src_dest, MESSAGE* msg) 
; ====================================================================
; Never call sendrec() directly, call send_recv() instead.
sendrec:
 mov eax, _NR_sendrec
 mov ebx, [esp + 4]  ; function
 mov ecx, [esp + 8]  ; src_dest
 mov edx, [esp + 12]  ; p_msg
 int INT_VECTOR_SYS_CALL
 ret

; ====================================================================================
;                          void write(char* buf, int len);
; ====================================================================================
write:
        mov     eax, _NR_write
        mov     ebx, [esp + 4]
        mov     ecx, [esp + 8]
        int     INT_VECTOR_SYS_CALL
        ret

kernel/systask.c

/*************************************************************************//**
 *****************************************************************************
 * @file   systask.c
 * @brief
 * @author Forrest Y. Yu
 * @date   2007
 *****************************************************************************
 *****************************************************************************/

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


/*****************************************************************************
 *                                task_sys
 *****************************************************************************/
/**
 * <Ring 1> The main loop of TASK SYS.
 *
 *****************************************************************************/
PUBLIC void task_sys()
{
 MESSAGE msg;
 while (1) {
  send_recv(RECEIVE, ANY, &msg);
  int src = msg.source;

  switch (msg.type) {
  case GET_TICKS:
   msg.RETVAL = ticks;
   send_recv(SEND, src, &msg);
   break;
  default:
   panic("unknown msg type");
   break;
  }
 }
}

kernel/tty.c

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

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

#define TTY_FIRST (tty_table)
#define TTY_END  (tty_table + NR_CONSOLES)

PRIVATE void init_tty(TTY* p_tty);
PRIVATE void tty_do_read(TTY* p_tty);
PRIVATE void tty_do_write(TTY* p_tty);
PRIVATE void put_key(TTY* p_tty, u32 key);

/*======================================================================*
                           task_tty
 *======================================================================*/
PUBLIC void task_tty()
{
 TTY* p_tty;

 init_keyboard();

 for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
  init_tty(p_tty);
 }
 select_console(0);
 while (1) {
  for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
   tty_do_read(p_tty);
   tty_do_write(p_tty);
  }
 }
}

/*======================================================================*
      init_tty
 *======================================================================*/
PRIVATE void init_tty(TTY* p_tty)
{
 p_tty->inbuf_count = 0;
 p_tty->p_inbuf_head = p_tty->p_inbuf_tail = p_tty->in_buf;

 init_screen(p_tty);
}

/*======================================================================*
    in_process
 *======================================================================*/
PUBLIC void in_process(TTY* p_tty, u32 key)
{
        char output[2] = {'\0', '\0'};

        if (!(key & FLAG_EXT)) {
  put_key(p_tty, key);
        }
        else {
                int raw_code = key & MASK_RAW;
                switch(raw_code) {
                case ENTER:
   put_key(p_tty, '\n');
   break;
                case BACKSPACE:
   put_key(p_tty, '\b');
   break;
                case UP:
                        if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {
    scroll_screen(p_tty->p_console, SCR_DN);
                        }
   break;
  case DOWN:
   if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {
    scroll_screen(p_tty->p_console, SCR_UP);
   }
   break;
  case F1:
  case F2:
  case F3:
  case F4:
  case F5:
  case F6:
  case F7:
  case F8:
  case F9:
  case F10:
  case F11:
  case F12:
   /* Alt + F1~F12 */
   if ((key & FLAG_ALT_L) || (key & FLAG_ALT_R)) {
    select_console(raw_code - F1);
   }
   break;
                default:
                        break;
                }
        }
}

/*======================================================================*
         put_key
*======================================================================*/
PRIVATE void put_key(TTY* p_tty, u32 key)
{
 if (p_tty->inbuf_count < TTY_IN_BYTES) {
  *(p_tty->p_inbuf_head) = key;
  p_tty->p_inbuf_head++;
  if (p_tty->p_inbuf_head == p_tty->in_buf + TTY_IN_BYTES) {
   p_tty->p_inbuf_head = p_tty->in_buf;
  }
  p_tty->inbuf_count++;
 }
}


/*======================================================================*
         tty_do_read
 *======================================================================*/
PRIVATE void tty_do_read(TTY* p_tty)
{
 if (is_current_console(p_tty->p_console)) {
  keyboard_read(p_tty);
 }
}


/*======================================================================*
         tty_do_write
 *======================================================================*/
PRIVATE void tty_do_write(TTY* p_tty)
{
 if (p_tty->inbuf_count) {
  char ch = *(p_tty->p_inbuf_tail);
  p_tty->p_inbuf_tail++;
  if (p_tty->p_inbuf_tail == p_tty->in_buf + TTY_IN_BYTES) {
   p_tty->p_inbuf_tail = p_tty->in_buf;
  }
  p_tty->inbuf_count--;

  out_char(p_tty->p_console, ch);
 }
}

/*======================================================================*
                              tty_write
*======================================================================*/
PUBLIC void tty_write(TTY* p_tty, char* buf, int len)
{
        char* p = buf;
        int i = len;

        while (i) {
                out_char(p_tty->p_console, *p++);
                i--;
        }
}

/*======================================================================*
                              sys_write
*======================================================================*/
PUBLIC int sys_write(char* buf, int len, PROCESS* p_proc)
{
        tty_write(&tty_table[p_proc->nr_tty], buf, len);
        return 0;
}

kernel/vsprintf.c

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

#include "type.h"
#include "const.h"
#include "string.h"

/*
 *  為更好地理解此函數的原理,可參考 printf 的注釋部分。
 */

/*======================================================================*
                                vsprintf
 *======================================================================*/
int vsprintf(char *buf, const char *fmt, va_list args)
{
 char* p;
 char tmp[256];
 va_list p_next_arg = args;

 for (p=buf;*fmt;fmt++) {
  if (*fmt != '%') {
   *p++ = *fmt;
   continue;
  }

  fmt++;

  switch (*fmt) {
  case 'x':
   itoa(tmp, *((int*)p_next_arg));
   strcpy(p, tmp);
   p_next_arg += 4;
   p += strlen(tmp);
   break;
  case 's':
   break;
  default:
   break;
  }
 }

 return (p - buf);
}

lib/misc.c

PUBLIC void assertion_failure(char *exp, char *file, char *base_file, int line)
{
 printl("%c assert(%s) failed: file: %s, base_file: %s, ln%d",
     MAG_CH_ASSERT,
     exp, file, base_file, line);

 spin("assertion_failure()");

 __asm__ __volatile__("ud2");
}

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 = objdump
CC  = gcc
LD  = ld
ASMBFLAGS = -I boot/include/
ASMKFLAGS = -I include/ -f elf
CFLAGS  = -I include/ -m32 -c -fno-builtin -Wall
#CFLAGS  = -I include/ -m32 -c -fno-builtin -fno-stack-protector
LDFLAGS  = -s  -melf_i386 -Ttext $(ENTRYPOINT)
DASMFLAGS = -D

# This Program
ORANGESBOOT = boot/boot.bin boot/loader.bin
ORANGESKERNEL = kernel.bin
OBJS  = kernel/kernel.o kernel/syscall.o kernel/start.o kernel/main.o\
   kernel/clock.o kernel/keyboard.o kernel/tty.o kernel/console.o\
   kernel/i8259.o kernel/global.o kernel/protect.o kernel/proc.o\
   kernel/systask.o\
   kernel/printf.o kernel/vsprintf.o\
   lib/kliba.o lib/klib.o lib/string.o lib/misc.o
DASMOUTPUT = kernel.bin.asm

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

# Default starting position
nop :
 @echo "why not \`make image' huh? :)"

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
 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/syscall.o : kernel/syscall.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/keyboard.o: kernel/keyboard.c
 $(CC) $(CFLAGS) -o $@ $<

kernel/tty.o: kernel/tty.c
 $(CC) $(CFLAGS) -o $@ $<

kernel/console.o: kernel/console.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 $@ $<

kernel/proc.o: kernel/proc.c
 $(CC) $(CFLAGS) -o $@ $<

kernel/printf.o: kernel/printf.c
 $(CC) $(CFLAGS) -o $@ $<

kernel/vsprintf.o: kernel/vsprintf.c
 $(CC) $(CFLAGS) -o $@ $<

kernel/systask.o: kernel/systask.c
 $(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/misc.o: lib/misc.c
 $(CC) $(CFLAGS) -o $@ $<

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

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

目錄結構

.
├── a.img
├── boot
│   ├── boot.asm
│   ├── include
│   │   ├── fat12hdr.inc
│   │   ├── load.inc
│   │   └── pm.inc
│   └── loader.asm
├── include
│   ├── console.h
│   ├── const.h
│   ├── global.h
│   ├── keyboard.h
│   ├── keymap.h
│   ├── proc.h
│   ├── protect.h
│   ├── proto.h
│   ├── sconst.inc
│   ├── string.h
│   ├── tty.h
│   └── type.h
├── kernel
│   ├── clock.c
│   ├── console.c
│   ├── global.c
│   ├── i8259.c
│   ├── kernel.asm
│   ├── keyboard.c
│   ├── main.c
│   ├── printf.c
│   ├── proc.c
│   ├── protect.c
│   ├── start.c
│   ├── syscall.asm
│   ├── systask.c
│   ├── tty.c
│   └── vsprintf.c
├── lib
│   ├── kliba.asm
│   ├── klib.c
│   ├── misc.c
│   └── string.asm
└── Makefile

留言

這個網誌中的熱門文章

用 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 $...