跳到主要內容

輸入/輸出系統-printf

printf 使用過程示意圖

程式碼

include/const.h (修改)

#define NR_SYS_CALL     2

include/global.h (新增)

extern  TASK            user_proc_table[];

include/proc.h (修改)

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;                  /* 用以指定此處理序的 TTY */
} PROCESS;

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

include/string.h (新增)

PUBLIC int strlen(char* p_str);

include/type.h (新增)

typedef char *   va_list;

kernel/proc.c (修改)

for (p = proc_table; p < proc_table+NR_TASKS+NR_PROCS; p++) {
for(p=proc_table;p < proc_table+NR_TASKS+NR_PROCS;p++) {

kernel/protect.c (修改)

for (i = 0; i < NR_TASKS+NR_PROCS; i++){

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

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     dx, ss
        mov     ds, dx
        mov     es, dx

        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
 push dword [p_proc_ready]
        sti

 push ecx
 push ebx
        call    [sys_call_table + eax * 4]
 add esp, 4 * 3

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

bits 32
[section .text]

; ====================================================================
;                              get_ticks
; ====================================================================
get_ticks:
 mov eax, _NR_get_ticks
 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/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/string.asm

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

[SECTION .text]

; 導出函數
global memcpy
global memset
global  strcpy
global  strlen


; ------------------------------------------------------------------------
; 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 結束-------------------------------------------------------------


; ------------------------------------------------------------------------
; int strlen(char* p_str);
; ------------------------------------------------------------------------
strlen:
        push    ebp
        mov     ebp, esp

        mov     eax, 0                  ; 字元串長度開始是 0
        mov     esi, [ebp + 8]          ; esi 指向首位址

.1:
        cmp     byte [esi], 0           ; 看 esi 指向的字元是否是 '\0'
        jz      .2                      ; 如果是 '\0',程序結束
        inc     esi                     ; 如果不是 '\0',esi 指向下一個字元
        inc     eax                     ;         並且,eax 自加一
        jmp     .1                      ; 如此循環

.2:
        pop     ebp
        ret                             ; 函數結束,返回
; ------------------------------------------------------------------------

Makefile (新增)

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

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

Makefile (修改)

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/printf.o kernel/vsprintf.o\
     lib/kliba.o lib/klib.o lib/string.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
│   ├── tty.c
│   └── vsprintf.c
├── lib
│   ├── kliba.asm
│   ├── klib.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 $...