0x09_自制操作系统My-OS实现Timer
一般机器都会有一个计时器的设备,在一定时间内不断发送中断信号,我们接收这个中断信号搞一个timer++这就是计时器了
把class06改07
naskfunc.asm
; naskfunc ; TAB=4 [FORMAT "WCOFF"] ; 制作目标文件的模式 [INSTRSET "i486p"] ; 使用到486为止的指令 [BITS 32] ; 3制作32位模式用的机器语言 [FILE "naskfunc.asm"] ; 文件名 GLOBAL _io_hlt,_write_mem8,_io_cli,_io_sti,_io_get8,_io_set8,_io_stihlt GLOBAL _io_load_eflags,_io_store_eflags,_asm_inthandler21 GLOBAL _load_gdtr, _load_idtr,_load_cr0,_store_cr0 GLOBAL _memtest_sub,_asm_inthandler20 EXTERN _inthandler21,_inthandler20 [SECTION .text] _io_hlt: ; void io_hlt(void); HLT RET _io_cli: ; void io_cli(void); CLI RET _io_sti: ; void io_sti(void); STI RET _io_get8: ; int io_get8(int port); MOV EDX,[ESP+4] ; port MOV EAX,0 IN AL,DX RET _io_set8: ; void io_set8(int port, int data); MOV EDX,[ESP+4] ; port MOV AL,[ESP+8] ; data OUT DX,AL RET _io_stihlt: ; void io_stihlt(void); STI HLT RET _write_mem8: ; void write_mem8(int addr, int data); MOV ECX,[ESP+4] ; taking content of add MOV AL,[ESP+8] ; taking content of data MOV [ECX],AL ; *ecx=al RET _io_load_eflags: ; int io_load_eflags(void); PUSHFD ; PUSH EFLAGS POP EAX RET _io_store_eflags: ; void io_store_eflags(int eflags); MOV EAX,[ESP+4] PUSH EAX POPFD ; POP EFLAGS RET _load_gdtr: ; void load_gdtr(int limit, int addr); MOV AX,[ESP+4] ; limit MOV [ESP+6],AX LGDT [ESP+6] RET _load_idtr: ; void load_idtr(int limit, int addr); MOV AX,[ESP+4] ; limit MOV [ESP+6],AX LIDT [ESP+6] RET _asm_inthandler21: PUSH ES PUSH DS PUSHAD MOV EAX,ESP PUSH EAX MOV AX,SS MOV DS,AX MOV ES,AX CALL _inthandler21 POP EAX POPAD POP DS POP ES IRETD _memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) PUSH EDI ; (由于还要使用EBX, ESI, EDI) PUSH ESI PUSH EBX MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; MOV EAX,[ESP+12+4] ; i = start; mts_loop: MOV EBX,EAX ADD EBX,0xffc ; p = i + 0xffc; MOV EDX,[EBX] ; old = *p; MOV [EBX],ESI ; *p = pat0; XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; CMP EDI,[EBX] ; if (*p != pat1) goto fin; JNE mts_fin XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; CMP ESI,[EBX] ; if (*p != pat0) goto fin; JNE mts_fin MOV [EBX],EDX ; *p = old; ADD EAX,0x1000 ; i += 0x1000; CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; JBE mts_loop POP EBX POP ESI POP EDI RET mts_fin: MOV [EBX],EDX ; *p = old; POP EBX POP ESI POP EDI RET _load_cr0: ; int load_cr0(void); MOV EAX,CR0 RET _store_cr0: ; void store_cr0(int cr0); MOV EAX,[ESP+4] MOV CR0,EAX RET _asm_inthandler20: PUSH ES PUSH DS PUSHAD MOV EAX,ESP PUSH EAX MOV AX,SS MOV DS,AX MOV ES,AX CALL _inthandler20 POP EAX POPAD POP DS POP ES IRETD
head.h
/*naskfunc.asm*/ void io_stihlt(); void io_hlt(void); void io_cli(void); void io_sti(void); int io_get8(int port); void io_set8(int port, int data); void write_mem8(int addr, int data); int io_load_eflags(void); void io_store_eflags(int eflags); int load_cr0(void); void store_cr0(int cr0); void load_gdtr(int limit, int addr); void load_idtr(int limit, int addr); void asm_inthandler20(void); void asm_inthandler21(void); /* asmhead.nas */ struct BOOTINFO { /* 0x0ff0-0x0fff */ char cyls; /* 启动区读磁盘读到此为止 */ char leds; /* 启动时键盘的LED的状态 */ char vmode; /* 显卡模式为多少位彩色 */ char reserve; short scrnx, scrny; /* 画面分辨率 */ char *vram; }; #define ADR_BOOTINFO 0x00000ff0 unsigned int memtest_sub(unsigned int start, unsigned int end); /*graphic.c*/ void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); void putfont8(char *vram, int xsize, int x, int y, char c, char *font); void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); /*font*/ extern char font[4096]; /* dsctbl.c */ struct SEGMENT_DESCRIPTOR { short limit_low, base_low; char base_mid, access_right; char limit_high, base_high; }; struct GATE_DESCRIPTOR { short offset_low, selector; char dw_count, access_right; short offset_high; }; void init_gdtidt(void); void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); #define ADR_IDT 0x0026f800 #define LIMIT_IDT 0x000007ff #define ADR_GDT 0x00270000 #define LIMIT_GDT 0x0000ffff #define ADR_BOTPAK 0x00280000 #define LIMIT_BOTPAK 0x0007ffff #define AR_DATA32_RW 0x4092 #define AR_CODE32_ER 0x409a #define AR_INTGATE32 0x008e /* pic.c */ void init_pic(void); #define PIC0_ICW1 0x0020 #define PIC0_OCW2 0x0020 #define PIC0_IMR 0x0021 #define PIC0_ICW2 0x0021 #define PIC0_ICW3 0x0021 #define PIC0_ICW4 0x0021 #define PIC1_ICW1 0x00a0 #define PIC1_OCW2 0x00a0 #define PIC1_IMR 0x00a1 #define PIC1_ICW2 0x00a1 #define PIC1_ICW3 0x00a1 #define PIC1_ICW4 0x00a1 /*interrupt.c*/ #define PORT_KEYDAT 0x0060 void inthandler21(int *esp); void inthandler20(int *esp); /*fifo.c*/ struct FIFO8 { unsigned char *buf; int p, q, size, free, flags; }; #define FLAGS_OVERRUN 0x0001 void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf); int fifo8_put(struct FIFO8 *fifo, unsigned char data); int fifo8_get(struct FIFO8 *fifo); int fifo8_status(struct FIFO8 *fifo); //memory.c #define MEMMAN_ADDR 0x003c0000 #define EFLAGS_AC_BIT 0x00040000 #define CR0_CACHE_DISABLE 0x60000000 #define MEMMAN_FREES 4090 /* 大约是32KB*/ struct FREEINFO { /* 可用信息 */ unsigned int addr, size; }; struct MEMMAN { /* 内存管理 */ int frees, maxfrees, lostsize, losts; struct FREEINFO free[MEMMAN_FREES]; }; void memman_init(struct MEMMAN *man); unsigned int memman_total(struct MEMMAN *man); unsigned int memtest(unsigned int start, unsigned int end); int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); void memory(); unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size); /*timer.c*/ #define PIT_CTRL 0x0043 #define PIT_CNT0 0x0040 struct TIMERCTL { unsigned int count; };
timer.c
#include "include/head.h" struct TIMERCTL timerctl; void init_pit(void) { io_set8(PIT_CTRL, 0x34); io_set8(PIT_CNT0, 0x9c); io_set8(PIT_CNT0, 0x2e); timerctl.count = 0; return; }
interupt.c
#include "include/head.h" struct FIFO8 keyfifo; extern struct TIMERCTL timerctl; void inthandler21(int *esp) /* 来自PS/2键盘的中断 */ { unsigned char data; io_set8(PIC0_OCW2, 0x61); /* 通知PIC,说IRQ-01的受理已经完成 */ data = io_get8(PORT_KEYDAT); fifo8_put(&keyfifo, data); return; } void inthandler20(int *esp) { io_set8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收完了的信息通知给PIC */ /* 暂时什么也不做 */ timerctl.count++; return; }
注册idt
/* GDT、IDT、descriptor table 关系处理 */ #include "include/head.h" void init_gdtidt(void) { struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; int i; /* GDT初始化 */ for (i = 0; i <= LIMIT_GDT / 8; i++) { set_segmdesc(gdt + i, 0, 0, 0); } set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); load_gdtr(LIMIT_GDT, ADR_GDT); /* IDT初始化 */ for (i = 0; i <= LIMIT_IDT / 8; i++) { set_gatedesc(idt + i, 0, 0, 0); } load_idtr(LIMIT_IDT, ADR_IDT); /* IDT设置*/ set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); /* IDT的设定 */ return; } void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) { if (limit > 0xfffff) { ar |= 0x8000; /* G_bit = 1 */ limit /= 0x1000; } sd->limit_low = limit & 0xffff; sd->base_low = base & 0xffff; sd->base_mid = (base >> 16) & 0xff; sd->access_right = ar & 0xff; sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); sd->base_high = (base >> 24) & 0xff; return; } void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) { gd->offset_low = offset & 0xffff; gd->selector = selector; gd->dw_count = (ar >> 8) & 0xff; gd->access_right = ar & 0xff; gd->offset_high = (offset >> 16) & 0xffff; return; }
main.c
#include "include/head.h" #include <string.h> struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; extern struct FIFO8 keyfifo; extern struct TIMERCTL timerctl; void Main(void){ int i;char s[256]; char keybuf[256]; init_gdtidt(); init_pic(); io_sti(); fifo8_init(&keyfifo, 32, keybuf); init_palette(); init_pit(); io_set8(PIC0_IMR, 0xf8); /* 开放PIC1和键盘中断(11111001) */ memory(); for (;;) { io_hlt(); boxfill8(binfo->vram, binfo->scrnx, 1,0,24,binfo->scrnx, 40); sprintf(s, "%010d", timerctl.count); putfonts8_asc(binfo->vram, binfo->scrnx, 24, 24, 7, s); if (fifo8_status(&keyfifo)== 0) { io_stihlt(); } else { int i = fifo8_get(&keyfifo); io_sti(); if(i<129) { boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny); sprintf(s, "key = %d", i); putfonts8_asc(binfo->vram, binfo->scrnx, 8, 8, 7, s); }else{ boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny); sprintf(s, "key = -"); putfonts8_asc(binfo->vram, binfo->scrnx, 8, 8, 7, s); } } } }
最后在Makefile里面加入timer.obj
运行:
cd class07 ..\z_tools\make.exe run