const.h
#ifndef _CONST_H_
#define _CONST_H_
/* 函数类型 */
#define PUBLIC /* PUBLIC is the opposite of PRIVATE,宏展开了啥都没有,其实没有啥作用,只是提示一下阅读,该函数,类外可见 */
#define PRIVATE static /* static源文件可见 */
/* GDT 和 IDT 中描述符的个数 */
#define GDT_SIZE 128
#define IDT_SIZE 256
/* Boolean */
#define TRUE 1
#define FALSE 0
/* GDT 和 IDT 中描述符的个数 */
#define GDT_SIZE 128
#define IDT_SIZE 256
/* 权限 */
#define PRIVILEGE_KRNL 0
#define PRIVILEGE_TASK 1
#define PRIVILEGE_USER 3
/* 8259A interrupt controller ports. */
#define INT_M_CTL 0x20 /* I/O port for interrupt controller <Master> */
#define INT_M_CTLMASK 0x21 /* setting bits in this port disables ints <Master> */
#define INT_S_CTL 0xA0 /* I/O port for second interrupt controller <Slave> */
#define INT_S_CTLMASK 0xA1 /* setting bits in this port disables ints <Slave> */
#endif
kernel.asm
SELECTOR_KERNEL_CS equ 8
; 导入函数
extern cstart
extern exception_handler
extern spurious_irq
; 导入全局变量
extern gdt_ptr
extern idt_ptr
[SECTION .bss]
StackSpace resb 2 * 1024
StackTop: ; 栈顶
[section .text] ; 代码在此
global _start ; 导出 _start
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 段中
sgdt [gdt_ptr] ; cstart() 中将会用到 gdt_ptr
call cstart ; 在此函数中改变了gdt_ptr,让它指向新的GDT
lgdt [gdt_ptr] ; 使用新的GDT
lidt [idt_ptr] ; 使用IDT
ud2
jmp $
; 中断和异常 -- 硬件中断
; ---------------------------------
%macro hwint_master 1
push %1
call spurious_irq
add esp, 4
hlt
%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
klib.asm
[SECTION .data]
disp_pos dd 0
disp_pos_2 dd 0
[SECTION .text]
; 导出函数
global DspStr
global DspStrFixPos
global memcpy
global out_byte
global in_byte
; ========================================================================
; void DspStr(char * info);
; ========================================================================
DspStr:
push ebp
mov ebp, esp
mov esi, [ebp + 8] ; pszInfo
mov edi, [disp_pos]
mov ah, 0Fh
.1:
lodsb
test al, al
jz .2
cmp al, 0Ah ; 是回车吗?
jnz .3
push eax
mov eax, edi
mov bl, 160
div bl
and eax, 0FFh
inc eax
mov bl, 160
mul bl
mov edi, eax
pop eax
jmp .1
.3:
mov [gs:edi], ax
add edi, 2
jmp .1
.2:
mov [disp_pos], edi
pop ebp
ret
; ========================================================================
; void DspStrFixLn(int line, char * info);
; ========================================================================
DspStrFixPos:
push ebp
mov ebp, esp
mov ebx, [ebp + 8] ; pszLine
mov [disp_pos_2], ebx
mov esi, [ebp + 12] ; pszInfo
mov edi, ebx;[disp_pos_2]
mov ah, 0Fh
.1:
lodsb
test al, al
jz .2
cmp al, 0Ah ; 是回车吗?
jnz .3
push eax
mov eax, edi
mov bl, 160
div bl
and eax, 0FFh
inc eax
mov bl, 160
mul bl
mov edi, eax
pop eax
jmp .1
.3:
mov [gs:edi], ax
add edi, 2
jmp .1
.2:
;mov [disp_pos_2], edi
pop ebp
ret
; 导出函数
; global memcpy
; ========================================================================
; void disp_color_str(char * info, int color);
; ========================================================================
disp_color_str:
push ebp
mov ebp, esp
mov esi, [ebp + 8] ; pszInfo
mov edi, [disp_pos]
mov ah, [ebp + 12] ; color
.1:
lodsb
test al, al
jz .2
cmp al, 0Ah ; 是回车吗?
jnz .3
push eax
mov eax, edi
mov bl, 160
div bl
and eax, 0FFh
inc eax
mov bl, 160
mul bl
mov edi, eax
pop eax
jmp .1
.3:
mov [gs:edi], ax
add edi, 2
jmp .1
.2:
mov [disp_pos], edi
pop ebp
ret
; ------------------------------------------------------------------------
; void* memcpy(void* es:pDest, void* ds:pSrc, int iSize);
; ------------------------------------------------------------------------
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 out_byte(t_port port, t_8 value);
; ========================================================================
out_byte:
mov edx, [esp + 4] ; port
mov al, [esp + 4 + 4] ; value
out dx, al
nop ; 一点延迟
nop
ret
; ========================================================================
; t_8 in_byte(t_port port);
; ========================================================================
in_byte:
mov edx, [esp + 4] ; port
xor eax, eax
in al, dx
nop ; 一点延迟
nop
ret
protect.h
#ifndef _PROTECT_H_
#define _PROTECT_H_
/* 存储段描述符/系统段描述符 */
typedef struct s_descriptor { /* 共 8 个字节 */
t_16 limit_low; /* Limit */
t_16 base_low; /* Base */
t_8 base_mid; /* Base */
t_8 attr1; /* P(1) DPL(2) DT(1) TYPE(4) */
t_8 limit_high_attr2; /* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */
t_8 base_high; /* Base */
} DESCRIPTOR;
/* 门描述符 */
typedef struct s_gate {
t_16 offset_low; /* Offset Low */
t_16 selector; /* Selector */
t_8 dcount; /* 该字段只在调用门描述符中有效。
如果在利用调用门调用子程序时引起特权级的转换和堆栈的改变,需要将外层堆栈中的参数复制到内层堆栈。
该双字计数字段就是用于说明这种情况发生时,要复制的双字参数的数量。 */
t_8 attr; /* P(1) DPL(2) DT(1) TYPE(4) */
t_16 offset_high; /* Offset High */
} GATE;
/* 中断向量 */
#define INT_VECTOR_IRQ0 0x20
#define INT_VECTOR_IRQ8 0x28
#endif
start.c
#include "type.h"
#include "const.h"
#include "protect.h"
/* 选择子 */
#define SELECTOR_DUMMY 0 // ┓
#define SELECTOR_FLAT_C 0x08 // ┣ LOADER 里面已经确定了的.
#define SELECTOR_FLAT_RW 0x10 // ┃
#define SELECTOR_VIDEO (0x18+3) // ┛<-- RPL=3
#define DA_386IGate 0x8E /* 386 中断门类型值 */
#define SELECTOR_KERNEL_CS SELECTOR_FLAT_C
#define SELECTOR_KERNEL_DS SELECTOR_FLAT_RW
PUBLIC void* memcpy(void* pDst, void* pSrc, int iSize);
PUBLIC void DspStr(char * pszInfo);
PUBLIC void DspStrFixPos(int line, char * pszInfo);
PUBLIC int sprintf(char *buf, const char *fmt, ...);
PRIVATE void memcpy_gdt();
PUBLIC void init_idt();
PUBLIC void init_prot();
PUBLIC void init_8259A();
PUBLIC void spurious_irq(int irq);
PUBLIC void exception_handler(int vec_no, int err_code, int eip, int cs, int eflags);
PUBLIC char * itoa(char * str, int num);
//PUBLIC void disp_int(int input);
/* 本文件内函数声明 */
PRIVATE void init_idt_desc(unsigned char vector, t_8 desc_type, t_pf_int_handler handler, unsigned char privilege);
//extern int disp_pos;
/* 中断处理函数 */
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();
PUBLIC void init_prot();
// 中断
void out_byte(t_port port, t_8 value);
t_8 in_byte(t_port port);
PUBLIC t_8 gdt_ptr[6]; // 0~15:Limit 16~47:Base
PUBLIC DESCRIPTOR gdt[GDT_SIZE];
PUBLIC t_8 idt_ptr[6]; // 0~15:Limit 16~47:Base
PUBLIC GATE idt[IDT_SIZE];
char *str0 = "hello os world, last line";
char *str1 = "hello os world, line111\n";
static char buf[1024]; // 显示用临时缓冲区
/*======================================================================*/
PUBLIC void cstart(){
//DspStrFixPos((80*20+0)*2, str0);
memcpy_gdt();
for(int i=0; i<100; i++){
sprintf(buf, "hello os printk year is %d, month is %d, day is %d i is %d\n", 2020, 11, 22, i);
DspStrFixPos((80*24+0)*2, buf);
}
//sprintf(buf, "hello os printk year is %d, month is %d, day is %d\n", 2020, 11, 8);
//DspStrFixPos(12, buf);
//sprintf(buf, "hello os sprintf, time is %d:%d\n", 14, 38);
//DspStrFixPos(13, buf);
}
PUBLIC void memcpy_gdt() {
// 将 LOADER 中的 GDT 复制到新的 GDT 中
memcpy( &gdt, // New GDT
(void*)(*((t_32*)(&gdt_ptr[2]))), // Base of Old GDT
*((t_16*)(&gdt_ptr[0])) + 1 // Limit of Old GDT
);
// gdt_ptr[6] 共 6 个字节:0~15:Limit 16~47:Base。用作 sgdt 以及 lgdt 的参数。
t_16* p_gdt_limit = (t_16*)(&gdt_ptr[0]);
t_32* p_gdt_base = (t_32*)(&gdt_ptr[2]);
*p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1;
*p_gdt_base = (t_32)&gdt;
}
PUBLIC void init_idt() {
init_prot();
// idt_ptr[6] 共 6 个字节:0~15:Limit 16~47:Base。用作 sidt 以及 lidt 的参数。
t_16* p_idt_limit = (t_16*)(&idt_ptr[0]);
t_32* p_idt_base = (t_32*)(&idt_ptr[2]);
*p_idt_limit = IDT_SIZE * sizeof(GATE) - 1;
*p_idt_base = (t_32)&idt;
}
/*======================================================================*
init_8259A
*======================================================================*/
PUBLIC void init_8259A(){
out_byte(INT_M_CTL, 0x11); // Master 8259, ICW1.
out_byte(INT_S_CTL, 0x11); // Slave 8259, ICW1.
out_byte(INT_M_CTLMASK, INT_VECTOR_IRQ0); // Master 8259, ICW2. 设置 '主8259' 的中断入口地址为 0x20.
out_byte(INT_S_CTLMASK, INT_VECTOR_IRQ8); // Slave 8259, ICW2. 设置 '从8259' 的中断入口地址为 0x28
out_byte(INT_M_CTLMASK, 0x4); // Master 8259, ICW3. IR2 对应 '从8259'.
out_byte(INT_S_CTLMASK, 0x2); // Slave 8259, ICW3. 对应 '主8259' 的 IR2.
out_byte(INT_M_CTLMASK, 0x1); // Master 8259, ICW4.
out_byte(INT_S_CTLMASK, 0x1); // Slave 8259, ICW4.
out_byte(INT_M_CTLMASK, 0xFD); // Master 8259, OCW1.
out_byte(INT_S_CTLMASK, 0xFF); // Slave 8259, OCW1.
}
/*======================================================================*
spurious_irq
*======================================================================*/
PUBLIC void spurious_irq(int irq){
//disp_str("spurious_irq: ");
//disp_int(irq);
//disp_str("\n");
sprintf(buf, "spurious_irq is %d\n", irq);
DspStrFixPos((80*24+0)*2, buf);
}
/*======================================================================*
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++){
DspStr(" ");
}
//disp_pos = 0;
DspStr("Exception! --> ");
DspStr(err_description[vec_no]);
DspStr("\n\n");
DspStr("EFLAGS:");
//disp_int(eflags);
sprintf(buf, "%d", eflags);
DspStr(buf);
DspStr("CS:");
//disp_int(cs);
sprintf(buf, "%d", cs);
DspStr(buf);
DspStr("EIP:");
//disp_int(eip);
sprintf(buf, "%d", eip);
DspStr(buf);
if(err_code != 0xFFFFFFFF){
DspStr("Error code:");
//disp_int(err_code);
sprintf(buf, "%d", err_code);
DspStr(buf);
}
}
/*======================================================================*
itoa
*======================================================================*/
PUBLIC char * itoa(char * str, int num)/* 数字前面的 0 不被显示出来, 比如 0000B800 被显示成 B800 */
{
char * p = str;
char ch;
int i;
t_bool flag = FALSE;
*p++ = '0';
*p++ = 'x';
if(num == 0){
*p++ = '0';
}
else{
for(i=28;i>=0;i-=4){
ch = (num >> i) & 0xF;
if(flag || (ch > 0)){
flag = TRUE;
ch += '0';
if(ch > '9'){
ch += 7;
}
*p++ = ch;
}
}
}
*p = 0;
return str;
}
/*======================================================================*
disp_int
*======================================================================*/
PUBLIC void disp_int(int input)
{
char output[16];
itoa(output, input);
//disp_str(output);
}
/*======================================================================*
init_idt_desc
*----------------------------------------------------------------------*
初始化 386 中断门
*======================================================================*/
PUBLIC void init_idt_desc(unsigned char vector, t_8 desc_type, t_pf_int_handler handler, unsigned char privilege)
{
GATE * p_gate = &idt[vector];
t_32 base = (t_32)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;
}
/*======================================================================*
init_prot
*----------------------------------------------------------------------*
初始化 IDT
*======================================================================*/
/* 中断向量 */
#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
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);
}
stdarg.h
#ifndef _STDARG_H
#define _STDARG_H
typedef char *va_list;
/* Amount of space required in an argument list for an arg of type TYPE.
TYPE may alternatively be an expression whose type is used. */
#define __va_rounded_size(TYPE) \
(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
#ifndef __sparc__
#define va_start(AP, LASTARG) \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#else
#define va_start(AP, LASTARG) \
(__builtin_saveregs (), \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif
void va_end (va_list); /* Defined in gnulib */
#define va_end(AP)
#define va_arg(AP, TYPE) \
(AP += __va_rounded_size (TYPE), \
*((TYPE *) (AP - __va_rounded_size (TYPE))))
#endif /* _STDARG_H */
string.h
#ifndef _STRING_H_
#define _STRING_H_
#ifndef NULL
#define NULL ((void *) 0)
#endif
#ifndef _SIZE_T
#define _SIZE_T
typedef unsigned int size_t;
#endif
extern inline int strlen(const char * s){
int i=0;
while(s[i] != '\0'){
i++;
}
return i;
}
extern inline char * strcpy(char * dst, const char *src){
char *ret = dst;
while ((*dst++=*src++)!='\0');
return ret;
}
#endif
type.h
#ifndef _TYPE_H_
#define _TYPE_H_
typedef unsigned int t_32;
typedef unsigned short t_16;
typedef unsigned char t_8;
typedef int t_bool;
typedef unsigned int t_port;
typedef void (*t_pf_int_handler) ();
#endif
vsprintf.c
#include "stdarg.h"
#include "string.h"
/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
// 将字符数字转换成整数。输入是数字串指针的指针,返回是结果的数值,另外指针将前移。
static int skip_atoi(const char **s) {
int i=0;
while (is_digit(**s)){
i = i*10 + *((*s)++) - '0'; // 这里导致指针前移
}
return i;
}
// 定义常用符号常数
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */
// 除法操作,输入:n为被除数,base为除数;结果:n为商,函数返回值为余数。
#define do_div(n,base) ({ \
int __res; \
__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
__res; })
// 将整数转换为指定进制的字符串。
// 输入:num-整数;base-进制;size-字符串长度;precision-数字长度(精度);type-类型选项。
// 输出:str字符串指针
static char * number(char * str, int num, int base, int size, int precision, int type){
char c,sign,tmp[36];
const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i;
// 根据类型定义字母集,默认是大写字母
if (type&SMALL) {
digits="0123456789abcdefghijklmnopqrstuvwxyz";
}
// 如果类型指出要左调整(靠左边界),则屏蔽类型中的填零标志。
// TODO: 这句没看懂?? 为什么要把最低位置为0
if (type&LEFT) {
type &= ~ZEROPAD;
}
// 本程序只能处理的进制范围:2-36
if (base<2 || base>36) {
return 0;
}
// TODO: 这句跟LEFT相关??
c = (type & ZEROPAD) ? '0' : ' ' ;
if (type&SIGN && num<0) {
sign='-';
num = -num;
} else{
sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0);
}
// 如果是带符号的,字符串宽度就减一
if (sign) {
size--;
}
if (type&SPECIAL) {
if (base==16) {
size -= 2;
} // 16进制需要减2,用于前面的0x
else if (base==8) {
size--;
} // 8进制的减1,因为前面的0
}
i=0;
if (num==0){
tmp[i++]='0';
} else {
while (num!=0){
tmp[i++]=digits[do_div(num,base)];
}
}
if (i>precision) {
precision=i;
} // 若字符个数大于精度值,精度值扩展为字符个数
size -= precision; // 宽度再减去用于存放数值字符的个数
// 将转换结果放在str中,如果类型中没有填零(ZEROPAD)和左靠齐标志,
// 则在str中首先填放剩余宽度值指出的空格数。若需要带符号位,则存入符号
if (!(type&(ZEROPAD+LEFT))){
while(size-->0){
*str++ = ' ';
}
}
if (sign){
*str++ = sign;
}
// 如果是特殊转换的处理,8进制和16进制分别填入0/0x/0X
if (type&SPECIAL) {
if (base==8){
*str++ = '0';
} else if (base==16) {
*str++ = '0';
*str++ = digits[33]; // 'x' or 'X'
}
}
// 如果类型么有左靠齐标志,则在剩余的宽度中存放c字符(‘0’或者空格)
if (!(type&LEFT)){
while(size-->0){
*str++ = c;
}
}
// 若i存有数值num的数字个数,若数字个数小于精度值,则str中放入 精度值-i 个'0'
while(i<precision--){
*str++ = '0';
}
// 将数值转换好的数字字符填入str中,共i个
while(i-->0){
*str++ = tmp[i];
}
// 若宽度值仍大于零,则表达类型标志中有左靠齐标志,则在剩余宽度中放入空格
while(size-->0){
*str++ = ' ';
}
return str;
}
// 格式化输出
int vsprintf(char *buf, const char *fmt, va_list args){
int len;
int i;
char * str; // 用于存放转换过程中的字符串
char *s;
int *ip;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
// 扫描格式字符串,对于不是 % 的就依次存入str
for (str=buf ; *fmt ; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
continue;
}
// 取得格式指示字符串中的标志域,并将标志常量放入flags变量中
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
// 取当前参数数字段宽度域值,放入field_width变量中,如果宽度域中是数值则直接取其为宽度值。
// 如果宽度域中是字符'*',表示下一个参数指定宽度。因此调用va_arg取宽度值。若此时宽度值
// 小于0,则该负数表示其带有标志域'-'标志(左靠齐),因此还需要在标志变量中填入该标志,并
// 将字段宽度值取为其绝对值。
/* get field width */
field_width = -1;
if (is_digit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int); // 这里有个bug,应插入++fmt。// TODO: 不懂
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}
// 取格式转换串的精度域,并放入precision变量中。精度域开始的标志是'.'.
// 其处理过程与上面宽度域的类似。如果精度域中是数值则直接取其为精度值。如果精度域中是
// 字符'*',表示下一个参数指定精度。因此调用va_arg取精度值。若此时宽度值小于0,则将
// 字段精度值取为0.
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier = *fmt;
++fmt;
}
// 分析转换指示符
switch (*fmt) {
// ‘c’ 表示对应参数应是字符。此时如果标志域表明不是左靠齐,则该字段前面
// 放入'宽度域值-1'个空格字符,然后再放入参数字符。如果宽度域大于0,
// 则表示为左靠齐,则在参数字符后面添加'宽度值-1'个空格字符
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
*str++ = ' ';
*str++ = (unsigned char) va_arg(args, int);
while (--field_width > 0)
*str++ = ' ';
break;
// 's'表示对应参数是字符串。首先取参数字符串的长度,若其超过了精度域值,
// 则扩展精度域=字符串长度。此时如果标志域表明不是左靠齐,则该字段前放入
// '宽度值-字符串长度'个空格字符。然后再放入参数字符串。如果宽度域还大于0,
// 则表示为左靠齐,则在参数字符串后面添加'宽度值-字符串长度'个空格字符。
case 's':
s = va_arg(args, char *);
len = strlen(s);
if (precision < 0)
precision = len;
else if (len > precision)
len = precision;
if (!(flags & LEFT))
while (len < field_width--)
*str++ = ' ';
for (i = 0; i < len; ++i)
*str++ = *s++;
while (len < field_width--)
*str++ = ' ';
break;
// 'o'表示8进制,通过number函数处理
case 'o':
str = number(str, va_arg(args, unsigned long), 8,
field_width, precision, flags);
break;
// 'p'表示一个指针类型,此时若该参数没有设置宽度域,默认宽度域为8
// 并且需要添零,然后用number函数处理
case 'p':
if (field_width == -1) {
field_width = 8;
flags |= ZEROPAD;
}
str = number(str,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
break;
// 'x'-转成16进制
case 'x':
flags |= SMALL;
case 'X':
str = number(str, va_arg(args, unsigned long), 16,
field_width, precision, flags);
break;
// 'd' & 'i' 表示带符号整数;'u' 表示无符号整数
case 'd':
case 'i':
flags |= SIGN;
case 'u':
str = number(str, va_arg(args, unsigned long), 10,
field_width, precision, flags);
break;
// 'n'-表示要把到目前为止转换输出字符数保存到对应参数指针指定的位置中。
// 首先利用va_arg()取得该参数指针,然后将已经转换好的字符数存到指向的位置
case 'n':
ip = va_arg(args, int *);
*ip = (str - buf);
break;
// 若格式转换不是 % ,则表示格式字符串有错,直接将一个“%”写入输出串中。
// 如果格式转换符的位置还有字符,则也直接将该字符写入输入串中,并返回继续处理
// 格式字符串,否则表示已经处理到格式字符串的结尾处,退出循环。
default:
if (*fmt != '%')
*str++ = '%';
if (*fmt)
*str++ = *fmt;
else
--fmt;
break;
}
}
*str = '\0'; // 字符串结尾字符:'\0'
return str-buf; // 返回转换好的长度值
}
// zhangkai
int sprintf(char *buf, const char *fmt, ...){
va_list args; // va_list是一个字符指针类型
int i;
va_start(args, fmt);
i=vsprintf(buf,fmt,args);
va_end(args);
return i;
}
网友评论